}
public boolean isInterested (String tableName) {
- return tableName.equalsIgnoreCase("Open_vSwitch");
+ return tableName.equalsIgnoreCase(Open_vSwitch.NAME.getName());
}
private void populateTunnelEndpoint (Node node, Open_vSwitch row) {
public void populateTunnelEndpoint (Node node) {
OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
try {
- Map<String, Table<?>> openvswitchTable = ovsdbTable.getRows(node, "Open_vSwitch");
+ Map<String, Table<?>> openvswitchTable = ovsdbTable.getRows(node, Open_vSwitch.NAME.getName());
if (openvswitchTable == null) {
logger.debug("Open_vSwitch table is null for Node {} ", node);
return;
String interfaceUUID = null;
int timeout = 6;
while ((interfaceUUID == null) && (timeout > 0)) {
- patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), status.getDescription());
+ patchPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), patchPortUUID);
OvsDBSet<UUID> interfaces = patchPort.getInterfaces();
if (interfaces == null || interfaces.size() == 0) {
// Wait for the OVSDB update to sync up the Local cache.
package org.opendaylight.ovsdb.neutron;
import java.net.HttpURLConnection;
-import java.util.List;
import org.opendaylight.controller.containermanager.ContainerConfig;
import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkAware;
return HttpURLConnection.HTTP_NOT_ACCEPTABLE;
}
- String networkID = convertNeutronIDToKey(network.getID());
-
- List<String> containers = containerManager.getContainerNames();
- if (containers.contains(networkID)) {
- logger.debug("Container with name {} exists", networkID);
- return HttpURLConnection.HTTP_CONFLICT;
- }
-
return HttpURLConnection.HTTP_CREATED;
}
logger.debug("Network creation failed {} ", result);
return;
}
- String networkId = convertNeutronIDToKey(network.getID());
-
- // Get Network Tenant ready - Containers and Internal Vlans.
- result = TenantNetworkManager.getManager().networkCreated(networkId);
- logger.debug("Neutron Network {} Created with Internal Vlan : {}", network.toString(), result);
- // Get internal network ready for Overlays
- InternalNetworkManager.getManager().prepareInternalNetwork(network);
+ TenantNetworkManager.getManager().networkCreated(network.getID());
}
/**
String portID = convertNeutronIDToKey(port.getID());
String portDesc = port.getName();
Boolean portAdminState = port.getAdminStateUp();
-/*
- * Add the Corresponding OF NodeConnector to the Container
- *
- ContainerConfig config = new ContainerConfig();
- config.setContainer(networkID);
- logger.debug("Adding Port {} to Container : {}", port.toString(), config.getContainer());
- List<String> ncList = new ArrayList<String>();
- ncList.add("OVS|"+ portID +"@OVS|"+networkID);
- config.addNodeConnectors(ncList);
- Status status = containerManager.addContainerEntry(networkID, ncList);
- if (!status.isSuccess()) {
- logger.error(" Port-ADD failed for tenant-id - {}," +
- " bridge-id - {}, port-id - {}, result - {} ",
- tenantID, networkID, portID, result);
- } else {
- logger.debug(" Port-ADD successful for tenant-id - {}," +
- " bridge-id - {}, port-id - {}, result - {} ",
- tenantID, networkID, portID, result);
- }
-*/
+ // Create Full Mesh Tunnels
+ /*
+ * Is this required ?
+ * The Tunnel Creation logic is completely owned by the Southbound handler at this point.
+
+ NeutronNetwork network = this.neutronNetworkCache.getNetwork(port.getNetworkUUID());
+ ProviderNetworkManager.getManager().createTunnels(network.getProviderNetworkType(),
+ network.getProviderSegmentationID());
+ */
logger.debug(" Port-ADD successful for tenant-id - {}," +
" network-id - {}, port-id - {}, result - {} ",
tenantID, networkID, portID, result);
+++ /dev/null
-package org.opendaylight.ovsdb.neutron;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ProviderNetworkManager {
- static final Logger logger = LoggerFactory.getLogger(ProviderNetworkManager.class);
- private static ProviderNetworkManager provider = new ProviderNetworkManager();
- private ProviderNetworkManager() {
- }
-
- public static ProviderNetworkManager getManager() {
- return provider;
- }
-}
--- /dev/null
+package org.opendaylight.ovsdb.neutron;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.ovsdb.lib.table.internal.Table;
+
+public class SouthboundEvent {
+ public enum Type { NODE, ROW };
+ public enum Action { ADD, UPDATE, DELETE };
+ private Type type;
+ private Action action;
+ private Node node;
+ private String tableName;
+ private String uuid;
+ private Table<?> row;
+ public SouthboundEvent(Node node, Action action) {
+ super();
+ this.type = Type.NODE;
+ this.action = action;
+ this.node = node;
+ }
+ public SouthboundEvent(Node node, String tableName, String uuid, Table<?> row, Action action) {
+ super();
+ this.type = Type.ROW;
+ this.action = action;
+ this.node = node;
+ this.tableName = tableName;
+ this.uuid = uuid;
+ this.row = row;
+ }
+ public Type getType() {
+ return type;
+ }
+ public Action getAction() {
+ return action;
+ }
+ public Node getNode() {
+ return node;
+ }
+ public String getTableName() {
+ return tableName;
+ }
+ public String getUuid() {
+ return uuid;
+ }
+ public Table<?> getRow() {
+ return row;
+ }
+ @Override
+ public String toString() {
+ return "SouthboundEvent [type=" + type + ", action=" + action + ", node=" + node + ", tableName=" + tableName
+ + ", uuid=" + uuid + ", row=" + row + "]";
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((action == null) ? 0 : action.hashCode());
+ result = prime * result + ((node == null) ? 0 : node.hashCode());
+ result = prime * result + ((tableName == null) ? 0 : tableName.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ SouthboundEvent other = (SouthboundEvent) obj;
+ if (action != other.action)
+ return false;
+ if (node == null) {
+ if (other.node != null)
+ return false;
+ } else if (!node.equals(other.node))
+ return false;
+ if (tableName == null) {
+ if (other.tableName != null)
+ return false;
+ } else if (!tableName.equals(other.tableName))
+ return false;
+ if (type != other.type)
+ return false;
+ if (uuid == null) {
+ if (other.uuid != null)
+ return false;
+ } else if (!uuid.equals(other.uuid))
+ return false;
+ return true;
+ }
+}
package org.opendaylight.ovsdb.neutron;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.table.Interface;
+import org.opendaylight.ovsdb.lib.table.Open_vSwitch;
+import org.opendaylight.ovsdb.lib.table.Port;
import org.opendaylight.ovsdb.lib.table.internal.Table;
+import org.opendaylight.ovsdb.neutron.provider.ProviderNetworkManager;
import org.opendaylight.ovsdb.plugin.OVSDBInventoryListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SouthboundHandler extends BaseHandler implements OVSDBInventoryListener {
static final Logger logger = LoggerFactory.getLogger(SouthboundHandler.class);
+ private Thread eventThread;
+ private BlockingQueue<SouthboundEvent> events;
+
+ void init() {
+ eventThread = new Thread(new EventHandler(), "SouthBound Event Thread");
+ this.events = new LinkedBlockingQueue<SouthboundEvent>();
+ }
+
+ void start() {
+ eventThread.start();
+ }
+
+ void stop() {
+ eventThread.interrupt();
+ }
@Override
public void nodeAdded(Node node) {
- logger.debug("NODE ADDED {}", node);
- AdminConfigManager.getManager().populateTunnelEndpoint(node);
- InternalNetworkManager.getManager().prepareInternalNetwork(node);
+ this.enqueueEvent(new SouthboundEvent(node, SouthboundEvent.Action.ADD));
}
@Override
public void nodeRemoved(Node node) {
- logger.debug("NODE REMOVED {}", node);
+ this.enqueueEvent(new SouthboundEvent(node, SouthboundEvent.Action.DELETE));
}
@Override
- public void rowAdded(Node node, String tableName, Table<?> row) {
- logger.debug("ROW ADDED {} , {}", node, row);
- /*
- * Should we support dynamic update of the Tunnel endpoint configuration ?
- *
- if (AdminConfigManager.getManager().isInterested(tableName)) {
- AdminConfigManager.getManager().populateTunnelEndpoint(node, tableName, row);
- }
- */
+ public void rowAdded(Node node, String tableName, String uuid, Table<?> row) {
+ this.enqueueEvent(new SouthboundEvent(node, tableName, uuid, row, SouthboundEvent.Action.ADD));
}
@Override
- public void rowRemoved(Node node, String tableName, Table<?> row) {
- logger.debug("ROW REMOVED {} , {}", node, row);
+ public void rowUpdated(Node node, String tableName, String uuid, Table<?> row) {
+ this.enqueueEvent(new SouthboundEvent(node, tableName, uuid, row, SouthboundEvent.Action.UPDATE));
+ }
+
+ @Override
+ public void rowRemoved(Node node, String tableName, String uuid, Table<?> row) {
+ this.enqueueEvent(new SouthboundEvent(node, tableName, uuid, row, SouthboundEvent.Action.DELETE));
+ }
+
+ private void enqueueEvent (SouthboundEvent event) {
+ try {
+ events.put(event);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ }
+ private class EventHandler implements Runnable {
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ SouthboundEvent ev = events.take();
+ switch (ev.getType()) {
+ case NODE:
+ ProcessNodeUpdate(ev.getNode(), ev.getAction());
+ case ROW:
+ ProcessRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(), ev.getAction());
+ break;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public void ProcessNodeUpdate(Node node, SouthboundEvent.Action action) {
+ if (action == SouthboundEvent.Action.DELETE) return;
+ logger.trace("Process Node added {}", node);
+ InternalNetworkManager.getManager().prepareInternalNetwork(node);
+ }
+
+ private void ProcessRowUpdate(Node node, String tableName, String uuid, Table<?> row,
+ SouthboundEvent.Action action) {
+ if (action == SouthboundEvent.Action.DELETE) return;
+
+ if (Interface.NAME.getName().equalsIgnoreCase(tableName)) {
+ logger.debug("trace {} Added / Updated {} , {}, {}", tableName, node, uuid, row);
+ Interface intf = (Interface)row;
+ NeutronNetwork network = TenantNetworkManager.getManager().getTenantNetworkForInterface(intf);
+ if (network != null) {
+ int vlan = TenantNetworkManager.getManager().networkCreated(network.getID());
+ logger.trace("Neutron Network {} Created with Internal Vlan : {}", network.toString(), vlan);
+
+ String portUUID = this.getPortIdForInterface(node, uuid, intf);
+ if (portUUID != null) {
+ TenantNetworkManager.getManager().programTenantNetworkInternalVlan(node, portUUID, network);
+ }
+ this.createTunnels(node, uuid, intf);
+ }
+ } else if (Port.NAME.getName().equalsIgnoreCase(tableName)) {
+ logger.debug("trace {} Added / Updated {} , {}, {}", tableName, node, uuid, row);
+ Port port = (Port)row;
+ Set<UUID> interfaceUUIDs = port.getInterfaces();
+ for (UUID intfUUID : interfaceUUIDs) {
+ logger.trace("Scanning interface "+intfUUID);
+ try {
+ Interface intf = (Interface)this.ovsdbConfigService.getRow(node, Interface.NAME.getName(), intfUUID.toString());
+ NeutronNetwork network = TenantNetworkManager.getManager().getTenantNetworkForInterface(intf);
+ if (network != null) {
+ TenantNetworkManager.getManager().programTenantNetworkInternalVlan(node, uuid, network);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ } else if (Open_vSwitch.NAME.getName().equalsIgnoreCase(tableName)) {
+ logger.debug("trace {} Added / Updated {} , {}, {}", tableName, node, uuid, row);
+ AdminConfigManager.getManager().populateTunnelEndpoint(node);
+ try {
+ Map<String, Table<?>> interfaces = this.ovsdbConfigService.getRows(node, Interface.NAME.getName());
+ if (interfaces != null) {
+ for (String intfUUID : interfaces.keySet()) {
+ Interface intf = (Interface) interfaces.get(intfUUID);
+ createTunnels(node, intfUUID, intf);
+ }
+ }
+ } catch (Exception e) {
+ logger.error("Error fetching Interface Rows for node {}", node);
+ }
+ }
+ }
+
+ private void createTunnels (Node node, String uuid, Interface intf) {
+ if (AdminConfigManager.getManager().getTunnelEndPoint(node) == null) {
+ logger.error("Tunnel end-point configuration missing. Please configure it in Open_vSwitch Table");
+ return;
+ }
+ NeutronNetwork network = TenantNetworkManager.getManager().getTenantNetworkForInterface(intf);
+ if (network != null) {
+ ProviderNetworkManager.getManager().createTunnels(network.getProviderNetworkType(),
+ network.getProviderSegmentationID());
+ }
+ }
+
+ private String getPortIdForInterface (Node node, String uuid, Interface intf) {
+ try {
+ Map<String, Table<?>> ports = this.ovsdbConfigService.getRows(node, Port.NAME.getName());
+ if (ports == null) return null;
+ for (String portUUID : ports.keySet()) {
+ Port port = (Port)ports.get(portUUID);
+ Set<UUID> interfaceUUIDs = port.getInterfaces();
+ logger.trace("Scanning Port {} to identify interface : {} ",port, uuid);
+ for (UUID intfUUID : interfaceUUIDs) {
+ if (intfUUID.toString().equalsIgnoreCase(uuid)) {
+ logger.trace("Found Interafce {} -> {}", uuid, portUUID);
+ return portUUID;
+ }
+ }
+ }
+ } catch (Exception e) {
+ logger.debug("Failed to add Port tag for for Intf {}",intf, e);
+ }
+ return null;
}
}
package org.opendaylight.ovsdb.neutron;
+import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
+import java.util.Set;
import org.opendaylight.controller.containermanager.ContainerConfig;
import org.opendaylight.controller.containermanager.ContainerFlowConfig;
import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
+import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.ServiceHelper;
import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.table.Bridge;
+import org.opendaylight.ovsdb.lib.table.Interface;
+import org.opendaylight.ovsdb.lib.table.Port;
+import org.opendaylight.ovsdb.lib.table.internal.Table;
+import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
static final Logger logger = LoggerFactory.getLogger(TenantNetworkManager.class);
private static final int MAX_VLAN = 4096;
+ private static final String EXTERNAL_ID_VM_ID = "vm-id";
+ private static final String EXTERNAL_ID_INTERFACE_ID = "iface-id";
+ private static final String EXTERNAL_ID_VM_MAC = "attached-mac";
private static TenantNetworkManager tenantHelper = new TenantNetworkManager();
private Queue<Integer> internalVlans = new LinkedList<Integer>();
private Map<String, Integer> tenantVlanMap = new HashMap<String, Integer>();
}
public int getInternalVlan (String networkId) {
- return tenantVlanMap.get(networkId);
+ Integer vlan = tenantVlanMap.get(networkId);
+ if (vlan == null) return 0;
+ return vlan.intValue();
}
public int networkCreated (String networkId) {
+ IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
+ if (containerManager == null) {
+ logger.error("ContainerManager is null. Failed to create Container for {}", networkId);
+ return 0;
+ }
int internalVlan = this.assignInternalVlan(networkId);
if (internalVlan != 0) {
ContainerConfig config = new ContainerConfig();
- config.setContainer(networkId);
+ config.setContainer(BaseHandler.convertNeutronIDToKey(networkId));
+ Status status = containerManager.addContainer(config);
+ logger.debug("Container Creation Status for {} : {}", networkId, status.toString());
+
ContainerFlowConfig flowConfig = new ContainerFlowConfig("InternalVlan", internalVlan+"",
null, null, null, null, null);
List<ContainerFlowConfig> containerFlowConfigs = new ArrayList<ContainerFlowConfig>();
containerFlowConfigs.add(flowConfig);
- config.addContainerFlows(containerFlowConfigs);
- IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
- if (containerManager != null) {
- Status status = containerManager.addContainer(config);
- logger.debug("Network Creation Status : {}", status.toString());
- } else {
- logger.error("ContainerManager is null. Failed to create Container for {}", networkId);
- }
+ containerManager.addContainerFlows(BaseHandler.convertNeutronIDToKey(networkId), containerFlowConfigs);
}
return internalVlan;
}
+
+ /**
+ * Are there any TenantNetwork VM present on this Node ?
+ * This method uses Interface Table's external-id field to locate the VM.
+ */
+ public boolean isTenantNetworkPresentInNode(Node node, String segmentationId) {
+ String networkId = this.getNetworkIdForSegmentationId(segmentationId);
+ if (networkId == null) {
+ logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
+ return false;
+ }
+ int internalVlan = this.getInternalVlan(networkId);
+ if (internalVlan == 0) {
+ logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
+ return false;
+ }
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ try {
+ /*
+ // Vlan Tag based identification
+ Map<String, Table<?>> portTable = ovsdbTable.getRows(node, Port.NAME.getName());
+ if (portTable == null) {
+ logger.debug("Port table is null for Node {} ", node);
+ return false;
+ }
+
+ for (Table<?> row : portTable.values()) {
+ Port port = (Port)row;
+ Set<BigInteger> tags = port.getTag();
+ if (tags.contains(internalVlan)) {
+ logger.debug("Tenant Network {} with Segmenation-id {} is present in Node {} / Port {}",
+ networkId, segmentationId, node, port);
+ return true;
+ }
+ }
+ */
+ // External-id based more accurate VM Location identification
+ Map<String, Table<?>> ifTable = ovsdbTable.getRows(node, Interface.NAME.getName());
+ if (ifTable == null) {
+ logger.debug("Interface table is null for Node {} ", node);
+ return false;
+ }
+
+ for (Table<?> row : ifTable.values()) {
+ Interface intf = (Interface)row;
+ Map<String, String> externalIds = intf.getExternal_ids();
+ if (externalIds != null) {
+ if (this.isInterfacePresentInTenantNetwork(externalIds.get(EXTERNAL_ID_INTERFACE_ID), networkId)) {
+ logger.debug("Tenant Network {} with Segmenation-id {} is present in Node {} / Interface {}",
+ networkId, segmentationId, node, intf);
+ return true;
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ logger.debug("Tenant Network {} with Segmenation-id {} is NOT present in Node {}",
+ networkId, segmentationId, node);
+
+ return false;
+ }
+
+ private String getNetworkIdForSegmentationId (String segmentationId) {
+ INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
+ List <NeutronNetwork> networks = neutronNetworkService.getAllNetworks();
+ for (NeutronNetwork network : networks) {
+ if (network.getProviderSegmentationID().equalsIgnoreCase(segmentationId)) return network.getNetworkUUID();
+ }
+ return null;
+ }
+
+ private boolean isInterfacePresentInTenantNetwork (String portId, String networkId) {
+ INeutronPortCRUD neutronPortService = (INeutronPortCRUD)ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
+ NeutronPort neutronPort = neutronPortService.getPort(portId);
+ if (neutronPort.getNetworkUUID().equalsIgnoreCase(networkId)) return true;
+ return false;
+ }
+
+ public NeutronNetwork getTenantNetworkForInterface (Interface intf) {
+ logger.trace("getTenantNetworkForInterface for {}", intf);
+ if (intf == null) return null;
+ Map<String, String> externalIds = intf.getExternal_ids();
+ logger.trace("externalIds {}", externalIds);
+ if (externalIds == null) return null;
+ String neutronPortId = externalIds.get(EXTERNAL_ID_INTERFACE_ID);
+ if (neutronPortId == null) return null;
+ INeutronPortCRUD neutronPortService = (INeutronPortCRUD)ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
+ NeutronPort neutronPort = neutronPortService.getPort(neutronPortId);
+ logger.trace("neutronPort {}", neutronPort);
+ if (neutronPort == null) return null;
+ INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
+ NeutronNetwork neutronNetwork = neutronNetworkService.getNetwork(neutronPort.getNetworkUUID());
+ logger.debug("{} mappped to {}", intf, neutronNetwork);
+ return neutronNetwork;
+ }
+
+ public void programTenantNetworkInternalVlan(Node node, String portUUID, NeutronNetwork network) {
+ int vlan = this.getInternalVlan(network.getID());
+ logger.debug("Programming Vlan {} on {}", vlan, portUUID);
+ if (vlan <= 0) {
+ logger.error("Unable to get an internalVlan for Network {}", network);
+ return;
+ }
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Port port = new Port();
+ OvsDBSet<BigInteger> tags = new OvsDBSet<BigInteger>();
+ tags.add(BigInteger.valueOf(vlan));
+ port.setTag(tags);
+ ovsdbTable.updateRow(node, Port.NAME.getName(), null, portUUID, port);
+ this.addPortToTenantNetworkContainer(node, portUUID, network);
+ }
+
+ private void addPortToTenantNetworkContainer(Node node, String portUUID, NeutronNetwork network) {
+ IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
+ if (containerManager == null) {
+ logger.error("ContainerManager is not accessible");
+ return;
+ }
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ try {
+ Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID);
+ if (port == null) {
+ logger.trace("Unable to identify Port with UUID {}", portUUID);
+ return;
+ }
+ Set<UUID> interfaces = port.getInterfaces();
+ if (interfaces == null) {
+ logger.trace("No interfaces available to fetch the OF Port");
+ return;
+ }
+ Bridge bridge = this.getBridgeIdForPort(node, portUUID);
+ if (bridge == null) {
+ logger.debug("Unable to spot Bridge for Port {} in node {}", port, node);
+ return;
+ }
+ Set<String> dpids = bridge.getDatapath_id();
+ if (dpids == null || dpids.size() == 0) return;
+ Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+
+ for (UUID intfUUID : interfaces) {
+ Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), intfUUID.toString());
+ if (intf == null) continue;
+ Set<BigInteger> of_ports = intf.getOfport();
+ if (of_ports == null) continue;
+ for (BigInteger of_port : of_ports) {
+ ContainerConfig config = new ContainerConfig();
+ config.setContainer(BaseHandler.convertNeutronIDToKey(network.getID()));
+ logger.debug("Adding Port {} to Container : {}", port.toString(), config.getContainer());
+ List<String> ncList = new ArrayList<String>();
+ Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+ NodeConnector nc = NodeConnector.fromStringNoNode(Node.NodeIDType.OPENFLOW.toString(),
+ Long.valueOf(of_port.longValue()).intValue()+"",
+ ofNode);
+ ncList.add(nc.toString());
+ config.addNodeConnectors(ncList);
+
+ Status status = containerManager.addContainerEntry(BaseHandler.convertNeutronIDToKey(network.getID()), ncList);
+
+ if (!status.isSuccess()) {
+ logger.error(" Failed {} : to add port {} to container - {}",
+ status, nc, network.getID());
+ } else {
+ logger.error(" Successfully added port {} to container - {}",
+ nc, network.getID());
+ }
+ }
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private Bridge getBridgeIdForPort (Node node, String uuid) {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ try {
+ Map<String, Table<?>> bridges = ovsdbTable.getRows(node, Bridge.NAME.getName());
+ if (bridges == null) return null;
+ for (String bridgeUUID : bridges.keySet()) {
+ Bridge bridge = (Bridge)bridges.get(bridgeUUID);
+ Set<UUID> portUUIDs = bridge.getPorts();
+ logger.trace("Scanning Bridge {} to identify Port : {} ",bridge, uuid);
+ for (UUID portUUID : portUUIDs) {
+ if (portUUID.toString().equalsIgnoreCase(uuid)) {
+ logger.trace("Found Port {} -> ", uuid, bridgeUUID);
+ return bridge;
+ }
+ }
+ }
+ } catch (Exception e) {
+ logger.debug("Failed to get BridgeId port {} in Node {}", uuid, node);
+ }
+ return null;
+ }
+
}
--- /dev/null
+package org.opendaylight.ovsdb.neutron.provider;
+
+import java.net.InetAddress;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
+import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
+import org.opendaylight.ovsdb.lib.notation.UUID;
+import org.opendaylight.ovsdb.lib.table.Bridge;
+import org.opendaylight.ovsdb.lib.table.Interface;
+import org.opendaylight.ovsdb.lib.table.Port;
+import org.opendaylight.ovsdb.lib.table.internal.Table;
+import org.opendaylight.ovsdb.neutron.AdminConfigManager;
+import org.opendaylight.ovsdb.neutron.InternalNetworkManager;
+import org.opendaylight.ovsdb.neutron.TenantNetworkManager;
+import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
+import org.opendaylight.ovsdb.plugin.OVSDBConfigService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+class OF10ProviderManager extends ProviderNetworkManager {
+ private static final Logger logger = LoggerFactory.getLogger(OF10ProviderManager.class);
+
+ @Override
+ public boolean hasPerTenantTunneling() {
+ return true;
+ }
+
+ private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
+ InetAddress srcTunnelEndPoint = AdminConfigManager.getManager().getTunnelEndPoint(node);
+ if (srcTunnelEndPoint == null) {
+ logger.error("Tunnel Endpoint not configured for Node {}", node);
+ return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
+ }
+
+ try {
+ if (!InternalNetworkManager.getManager().isInternalNetworkOverlayReady(node)) {
+ logger.error(node+" is not Overlay ready");
+ return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
+ }
+ } catch (Exception e) {
+ logger.error(node+" is not Overlay ready");
+ return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
+ }
+
+ if (!TenantNetworkManager.getManager().isTenantNetworkPresentInNode(node, tunnelKey)) {
+ logger.debug(node+" has no VM corresponding to segment "+ tunnelKey);
+ return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
+ }
+ return new Status(StatusCode.SUCCESS);
+ }
+
+ @Override
+ public Status createTunnels(String tunnelType, String tunnelKey, Node srcNode) {
+ Status status = getTunnelReadinessStatus(srcNode, tunnelKey);
+ if (!status.isSuccess()) return status;
+
+ IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
+ List<Node> nodes = connectionService.getNodes();
+ nodes.remove(srcNode);
+ for (Node dstNode : nodes) {
+ status = getTunnelReadinessStatus(dstNode, tunnelKey);
+ if (!status.isSuccess()) continue;
+ InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode);
+ InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode);
+ addTunnelPort(srcNode, tunnelType, src, dst, tunnelKey);
+ addTunnelPort(dstNode, tunnelType, dst, src, tunnelKey);
+ }
+ return new Status(StatusCode.SUCCESS);
+ }
+
+ private boolean isTunnelPresent(Node node, String tunnelName, String bridgeUUID) throws Exception {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
+ if (bridge != null) {
+ Set<UUID> ports = bridge.getPorts();
+ for (UUID portUUID : ports) {
+ Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString());
+ if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return true;
+ }
+ }
+ return false;
+ }
+
+ private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
+ try {
+ String bridgeUUID = null;
+ String tunnelBridgeName = AdminConfigManager.getManager().getTunnelBridgeName();
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
+ if (bridgeTable != null) {
+ for (String uuid : bridgeTable.keySet()) {
+ Bridge bridge = (Bridge)bridgeTable.get(uuid);
+ if (bridge.getName().equals(tunnelBridgeName)) {
+ bridgeUUID = uuid;
+ break;
+ }
+ }
+ }
+ if (bridgeUUID == null) {
+ logger.error("Could not find Bridge {} in {}", tunnelBridgeName, node);
+ return new Status(StatusCode.NOTFOUND, "Could not find "+tunnelBridgeName+" in "+node);
+ }
+ String portName = tunnelType+"-"+key+"-"+dst.getHostAddress();
+
+ if (this.isTunnelPresent(node, portName, bridgeUUID)) {
+ logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
+ return new Status(StatusCode.SUCCESS);
+ }
+
+ Port tunnelPort = new Port();
+ tunnelPort.setName(portName);
+ Status status = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, tunnelPort);
+ if (!status.isSuccess()) {
+ logger.error("Failed to insert Tunnel port {} in {}", portName, bridgeUUID);
+ return status;
+ }
+
+ String tunnelPortUUID = status.getDescription();
+
+ String interfaceUUID = null;
+ int timeout = 6;
+ while ((interfaceUUID == null) && (timeout > 0)) {
+ tunnelPort = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), tunnelPortUUID);
+ OvsDBSet<UUID> interfaces = tunnelPort.getInterfaces();
+ if (interfaces == null || interfaces.size() == 0) {
+ // Wait for the OVSDB update to sync up the Local cache.
+ Thread.sleep(500);
+ timeout--;
+ continue;
+ }
+ interfaceUUID = interfaces.toArray()[0].toString();
+ Interface intf = (Interface)ovsdbTable.getRow(node, Interface.NAME.getName(), interfaceUUID);
+ if (intf == null) interfaceUUID = null;
+ }
+
+ if (interfaceUUID == null) {
+ logger.error("Cannot identify Tunnel Interface for port {}/{}", portName, tunnelPortUUID);
+ return new Status(StatusCode.INTERNALERROR);
+ }
+
+ Interface tunInterface = new Interface();
+ tunInterface.setType(tunnelType);
+ OvsDBMap<String, String> options = new OvsDBMap<String, String>();
+ options.put("key", key);
+ options.put("local_ip", src.getHostAddress());
+ options.put("remote_ip", dst.getHostAddress());
+ tunInterface.setOptions(options);
+ status = ovsdbTable.updateRow(node, Interface.NAME.getName(), tunnelPortUUID, interfaceUUID, tunInterface);
+ logger.debug("Tunnel {} add status : {}", tunInterface, status);
+ return status;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new Status(StatusCode.INTERNALERROR);
+ }
+ }
+
+ @Override
+ public Status createTunnels(String tunnelType, String tunnelKey) {
+ IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
+ List<Node> nodes = connectionService.getNodes();
+ for (Node srcNode : nodes) {
+ this.createTunnels(tunnelType, tunnelKey, srcNode);
+ }
+ return null;
+ }
+}
--- /dev/null
+package org.opendaylight.ovsdb.neutron.provider;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.Status;
+
+
+class OF13ProviderManager extends ProviderNetworkManager {
+ @Override
+ public boolean hasPerTenantTunneling() {
+ return false;
+ }
+
+ @Override
+ public Status createTunnels(String tunnelType, String tunnelKey, Node source) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Status createTunnels(String tunnelType, String tunnelKey) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
--- /dev/null
+package org.opendaylight.ovsdb.neutron.provider;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class ProviderNetworkManager {
+ static final Logger logger = LoggerFactory.getLogger(ProviderNetworkManager.class);
+ private static ProviderNetworkManager provider;
+
+ public static ProviderNetworkManager getManager() {
+ if (provider != null) return provider;
+ if (System.getProperty("OF1.3_Provider") != null) {
+ provider = new OF13ProviderManager();
+ } else {
+ provider = new OF10ProviderManager();
+ }
+ return provider;
+ }
+
+ public abstract boolean hasPerTenantTunneling();
+ public abstract Status createTunnels(String tunnelType, String tunnelKey);
+ public abstract Status createTunnels(String tunnelType, String tunnelKey, Node source);
+}
package org.opendaylight.ovsdb.lib.notation;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
-
-import org.opendaylight.ovsdb.lib.notation.json.OVSDBTypesIDResolver;
import org.opendaylight.ovsdb.lib.notation.json.UUIDSerializer;
import org.opendaylight.ovsdb.lib.notation.json.UUIDStringConverter;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
@JsonDeserialize(contentConverter = UUIDStringConverter.class)
@JsonSerialize(using = UUIDSerializer.class)
/*
this.val = value;
}
+ @Override
public String toString() {
return val;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((val == null) ? 0 : val.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ UUID other = (UUID) obj;
+ if (val == null) {
+ if (other.val != null)
+ return false;
+ } else if (!val.equals(other.val))
+ return false;
+ return true;
+ }
}
package org.opendaylight.ovsdb.lib.table;
+import java.math.BigInteger;
+
import org.opendaylight.ovsdb.lib.notation.OvsDBMap;
import org.opendaylight.ovsdb.lib.notation.OvsDBSet;
import org.opendaylight.ovsdb.lib.table.internal.Table;
private String name;
private OvsDBMap<String, String> options;
private String type;
- private OvsDBSet<Integer> ofport;
+ private OvsDBSet<BigInteger> ofport;
private OvsDBSet<String> mac;
private OvsDBMap<String, Integer> statistics;
private OvsDBMap<String, String> status;
this.type = type;
}
- public OvsDBSet<Integer> getOfport() {
+ public OvsDBSet<BigInteger> getOfport() {
return ofport;
}
- public void setOfport(OvsDBSet<Integer> ofport) {
+ public void setOfport(OvsDBSet<BigInteger> ofport) {
this.ofport = ofport;
}
updateOFBridgeName(n, (Bridge)newRow);
}
if ((oldRow == null) && (inventoryListener != null)) {
- inventoryListener.rowAdded(n, name.getName(), newRow);
+ inventoryListener.rowAdded(n, name.getName(), uuid, newRow);
+ } else if (inventoryListener != null) {
+ inventoryListener.rowUpdated(n, name.getName(), uuid, newRow);
}
} else if (oldRow != null) {
if (inventoryListener != null) {
- inventoryListener.rowRemoved(n, name.getName(), oldRow);
+ inventoryListener.rowRemoved(n, name.getName(), uuid, oldRow);
}
db.removeRow(name.getName(), uuid);
}
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.core.Property;
import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
import org.opendaylight.ovsdb.lib.database.DatabaseSchema;
import org.opendaylight.ovsdb.lib.message.TableUpdates;
import org.opendaylight.ovsdb.lib.table.internal.Table;
-public interface InventoryServiceInternal {
+public interface InventoryServiceInternal extends IPluginInInventoryService {
public Map<String, Map<String, Table<?>>> getCache(Node n);
public Map<String, Table<?>> getTableCache(Node n, String tableName);
public Table<?> getRow (Node n, String tableName, String uuid);
public interface OVSDBInventoryListener {
public void nodeAdded(Node node);
public void nodeRemoved(Node node);
- public void rowAdded(Node node, String tableName, Table<?> row);
- public void rowRemoved(Node node, String tableName, Table<?> row);
+ public void rowAdded(Node node, String tableName, String uuid, Table<?> row);
+ public void rowUpdated(Node node, String tableName, String uuid, Table<?> row);
+ public void rowRemoved(Node node, String tableName, String uuid, Table<?> row);
}