<Import-Package>
org.opendaylight.controller.networkconfig.neutron,
org.opendaylight.controller.containermanager,
+ org.opendaylight.controller.forwardingrulesmanager,
org.opendaylight.controller.sal.core,
org.opendaylight.controller.sal.utils,
+ org.opendaylight.controller.sal.action,
org.opendaylight.ovsdb.plugin,
org.opendaylight.ovsdb.lib.notation,
org.opendaylight.ovsdb.lib.table,
<version>0.4.1-SNAPSHOT</version>
<artifactId>networkconfig.neutron</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>forwardingrulesmanager</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
private String tunnelBridgeName;
private String externalBridgeName;
private String tunnelEndpointConfigName;
+ private String patchToIntegration;
+ private String patchToTunnel;
private Map<Node, InetAddress> tunnelEndpoints;
// Refer to /etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini
private static String DEFAULT_INTEGRATION_BRIDGENAME = "br-int";
private static String DEFAULT_TUNNEL_BRIDGENAME = "br-tun";
private static String DEFAULT_EXTERNAL_BRIDGENAME = "br-ex";
+ private static String DEFAULT_PATCH_TO_INTEGRATION = "patch-int";
+ private static String DEFAULT_PATCH_TO_TUNNEL = "patch-tun";
private static String CONFIG_TUNNEL_ENDPOINT_CONFIG = "tunnel_endpoint_config_string";
private static String CONFIG_INTEGRATION_BRIDGENAME = "integration_bridge";
private static String CONFIG_TUNNEL_BRIDGENAME = "tunnel_bridge";
private static String CONFIG_EXTERNAL_BRIDGENAME = "external_bridge";
+ private static String CONFIG_PATCH_TO_INTEGRATION = "patch-int";
+ private static String CONFIG_PATCH_TO_TUNNEL = "patch-tun";
private static AdminConfigManager adminConfiguration = new AdminConfigManager();
integrationBridgeName = System.getProperty(CONFIG_INTEGRATION_BRIDGENAME);
tunnelBridgeName = System.getProperty(CONFIG_TUNNEL_BRIDGENAME);
externalBridgeName = System.getProperty(CONFIG_EXTERNAL_BRIDGENAME);
+ patchToIntegration = System.getProperty(CONFIG_PATCH_TO_INTEGRATION);
+ patchToTunnel = System.getProperty(CONFIG_PATCH_TO_TUNNEL);
if (tunnelEndpointConfigName == null) tunnelEndpointConfigName = DEFAULT_TUNNEL_ENDPOINT_CONFIG_STRING;
if (integrationBridgeName == null) integrationBridgeName = DEFAULT_INTEGRATION_BRIDGENAME;
if (tunnelBridgeName == null) tunnelBridgeName = DEFAULT_TUNNEL_BRIDGENAME;
if (externalBridgeName == null) externalBridgeName = DEFAULT_EXTERNAL_BRIDGENAME;
+ if (patchToIntegration == null) patchToIntegration = DEFAULT_PATCH_TO_INTEGRATION;
+ if (patchToTunnel == null) patchToTunnel = DEFAULT_PATCH_TO_TUNNEL;
}
public static AdminConfigManager getManager() {
this.externalBridgeName = externalBridgeName;
}
+ public String getPatchToIntegration() {
+ return patchToIntegration;
+ }
+
+ public void setPatchToIntegration(String patchToIntegration) {
+ this.patchToIntegration = patchToIntegration;
+ }
+
+ public String getPatchToTunnel() {
+ return patchToTunnel;
+ }
+
+ public void setPatchToTunnel(String patchToTunnel) {
+ this.patchToTunnel = patchToTunnel;
+ }
+
public InetAddress getTunnelEndPoint(Node node) {
return tunnelEndpoints.get(node);
}
package org.opendaylight.ovsdb.neutron;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
+import org.opendaylight.controller.sal.action.ActionType;
import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.EtherTypes;
+import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.ServiceHelper;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.sal.utils.StatusCode;
return internalNetwork;
}
- public boolean isInternalNetworkNeutronReady(Node node) throws Exception {
- OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
- Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
- if (bridgeTable != null) {
- for (Table<?> row : bridgeTable.values()) {
- Bridge bridge = (Bridge)row;
- if (bridge.getName().equals(AdminConfigManager.getManager().getIntegrationBridgeName())) return true;
+ public String getInternalBridgeUUID (Node node, String bridgeName) {
+ try {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
+ if (bridgeTable == null) return null;
+ for (String key : bridgeTable.keySet()) {
+ Bridge bridge = (Bridge)bridgeTable.get(key);
+ if (bridge.getName().equals(bridgeName)) return key;
}
+ } catch (Exception e) {
+ logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);
+ }
+ return null;
+ }
+
+ public boolean isInternalNetworkNeutronReady(Node node) throws Exception {
+ if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getIntegrationBridgeName()) != null) {
+ return true;
+ } else {
+ return false;
}
- return false;
}
public boolean isInternalNetworkOverlayReady(Node node) throws Exception {
- OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
- Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
- if (bridgeTable != null) {
- for (Table<?> row : bridgeTable.values()) {
- Bridge bridge = (Bridge)row;
- if (bridge.getName().equals(AdminConfigManager.getManager().getTunnelBridgeName())) return true;
- }
+ if (this.getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName()) != null) {
+ return true;
+ } else {
+ return false;
}
- return false;
}
public Status createInternalNetworkForOverlay(Node node) throws Exception {
Status status = ovsdbTable.insertRow(node, Bridge.NAME.getName(), null, brTun);
if (!status.isSuccess()) return status;
String bridgeUUID = status.getDescription();
+ // Set OF Controller
+ IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
+ connectionService.setOFController(node, bridgeUUID);
Port port = new Port();
port.setName(brTun.getName());
status = ovsdbTable.insertRow(node, Port.NAME.getName(), bridgeUUID, port);
- status = addPatchPort(node, bridgeUUID, "patch-int", "patch-tun");
+ String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
+ String patchTun = AdminConfigManager.getManager().getPatchToTunnel();
+
+ status = addPatchPort(node, bridgeUUID, patchInt, patchTun);
if (!status.isSuccess()) return status;
// Create the corresponding patch-tun port in br-int
for (String brIntUUID : bridges.keySet()) {
Bridge brInt = (Bridge) bridges.get(brIntUUID);
if (brInt.getName().equalsIgnoreCase(AdminConfigManager.getManager().getIntegrationBridgeName())) {
- return addPatchPort(node, brIntUUID, "patch-tun", "patch-int");
+ return addPatchPort(node, brIntUUID, patchTun, patchInt);
}
}
e.printStackTrace();
}
}
+
+ this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
+ this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
+ this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
+ }
+
+ private void initializeOFNormalFlowRules(Node node, String bridgeName) {
+ String brIntId = this.getInternalBridgeUUID(node, bridgeName);
+ if (brIntId == null) {
+ logger.error("Failed to initialize Flow Rules for {}", node);
+ return;
+ }
+ try {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
+ Set<String> dpids = bridge.getDatapath_id();
+ if (dpids == null || dpids.size() == 0) return;
+ Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+ Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+ IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
+ IForwardingRulesManager.class, "default", this);
+ String flowName = ActionType.HW_PATH.toString();
+ if (frm.getStaticFlow(flowName, ofNode) != null) {
+ logger.debug("Static Flow {} already programmed in the node {}", flowName, ofNode);
+ return;
+ }
+ FlowConfig flow = new FlowConfig();
+ flow.setName("IntegrationBridgeNormal");
+ flow.setNode(ofNode);
+ flow.setPriority("1");
+ List<String> normalAction = new ArrayList<String>();
+ normalAction.add(flowName);
+ flow.setActions(normalAction);
+ Status status = frm.addStaticFlow(flow);
+ logger.debug("Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
+ } catch (Exception e) {
+ logger.error("Failed to initialize Flow Rules for {}", node, e);
+ }
+ }
+
+ private void initializeLLDPFlowRules(Node node, String bridgeName) {
+ String brIntId = this.getInternalBridgeUUID(node, bridgeName);
+ if (brIntId == null) {
+ logger.error("Failed to initialize Flow Rules for {}", node);
+ return;
+ }
+ try {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
+ Set<String> dpids = bridge.getDatapath_id();
+ if (dpids == null || dpids.size() == 0) return;
+ Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+ Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+ IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
+ IForwardingRulesManager.class, "default", this);
+ String flowName = "PuntLLDP";
+ if (frm.getStaticFlow(flowName, ofNode) != null) {
+ logger.debug("Static Flow {} already programmed in the node {}", flowName, ofNode);
+ return;
+ }
+
+ List<String> puntAction = new ArrayList<String>();
+ puntAction.add(ActionType.CONTROLLER.toString());
+
+ FlowConfig allowLLDP = new FlowConfig();
+ allowLLDP.setInstallInHw(true);
+ allowLLDP.setName(flowName);
+ allowLLDP.setPriority("10");
+ allowLLDP.setNode(ofNode);
+ allowLLDP.setEtherType("0x" + Integer.toHexString(EtherTypes.LLDP.intValue())
+ .toUpperCase());
+ allowLLDP.setActions(puntAction);
+ Status status = frm.addStaticFlow(allowLLDP);
+ logger.debug("Flow Programming Status {} for Flow {} on {} / {}", status, allowLLDP, ofNode, node);
+ } catch (Exception e) {
+ logger.error("Failed to initialize Flow Rules for {}", node, e);
+ }
}
public void prepareInternalNetwork(NeutronNetwork network) {
}
}
+ public static List safe( List other ) {
+ return other == null ? Collections.EMPTY_LIST : other;
+ }
}
import java.net.HttpURLConnection;
-import org.opendaylight.controller.containermanager.ContainerConfig;
import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkAware;
import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
import org.slf4j.Logger;
result);
return;
}
- String networkID = convertNeutronIDToKey(network.getID());
-
- ContainerConfig config = new ContainerConfig();
- config.setContainer(networkID);
- containerManager.removeContainer(config);
+ TenantNetworkManager.getManager().networkDeleted(network.getID());
}
}
String tenantID = convertNeutronIDToKey(port.getTenantID());
String networkID = convertNeutronIDToKey(port.getNetworkUUID());
String portID = convertNeutronIDToKey(port.getID());
-/*
- * Delete the Corresponding OF NodeConnector from the Container
- *
- ContainerConfig config = new ContainerConfig();
- config.setContainer(networkID);
- List<String> ncList = new ArrayList<String>();
- ncList.add("OVS|"+ portID +"@OVS|"+networkID);
- config.addNodeConnectors(ncList);
- Status status = containerManager.removeContainerEntry(networkID, ncList);
- if (!status.isSuccess()) {
- logger.error(" PORT delete failed for tenant-id - {}, " +
- " bridge-id - {}, port-id - {}, result - {} ",
- tenantID, networkID, portID, status);
- } else {
- logger.error(" PORT delete successful for tenant-id - {}, " +
- " bridge-id - {}, port-id - {}, result - {} ",
- tenantID, networkID, portID, status);
- }
-*/
logger.debug(" PORT delete successful for tenant-id - {}, " +
" network-id - {}, port-id - {}", tenantID, networkID, portID);
NeutronNetwork network = TenantNetworkManager.getManager().getTenantNetworkForInterface(intf);
if (network != null) {
ProviderNetworkManager.getManager().createTunnels(network.getProviderNetworkType(),
- network.getProviderSegmentationID());
+ network.getProviderSegmentationID(), node, intf);
}
}
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";
+ public static final String EXTERNAL_ID_VM_ID = "vm-id";
+ public static final String EXTERNAL_ID_INTERFACE_ID = "iface-id";
+ public 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>();
+ private boolean enableContainer = false;
private TenantNetworkManager() {
for (int i = 1; i < MAX_VLAN ; i++) {
internalVlans.add(i);
}
+ String isTenantContainer = System.getProperty("TenantIsContainer");
+ if (isTenantContainer != null && isTenantContainer.equalsIgnoreCase("true")) {
+ enableContainer = true;
+ }
}
public static TenantNetworkManager getManager() {
}
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) {
+ if (enableContainer && internalVlan != 0) {
+ IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
+ if (containerManager == null) {
+ logger.error("ContainerManager is null. Failed to create Container for {}", networkId);
+ return 0;
+ }
+
ContainerConfig config = new ContainerConfig();
config.setContainer(BaseHandler.convertNeutronIDToKey(networkId));
Status status = containerManager.addContainer(config);
return false;
}
- private String getNetworkIdForSegmentationId (String segmentationId) {
+ public String getNetworkIdForSegmentationId (String segmentationId) {
INeutronNetworkCRUD neutronNetworkService = (INeutronNetworkCRUD)ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
List <NeutronNetwork> networks = neutronNetworkService.getAllNetworks();
for (NeutronNetwork network : networks) {
tags.add(BigInteger.valueOf(vlan));
port.setTag(tags);
ovsdbTable.updateRow(node, Port.NAME.getName(), null, portUUID, port);
- this.addPortToTenantNetworkContainer(node, portUUID, network);
+ if (enableContainer) this.addPortToTenantNetworkContainer(node, portUUID, network);
}
private void addPortToTenantNetworkContainer(Node node, String portUUID, NeutronNetwork network) {
return null;
}
+ public void networkDeleted(String id) {
+ if (!enableContainer) return;
+
+ IContainerManager containerManager = (IContainerManager)ServiceHelper.getGlobalInstance(IContainerManager.class, this);
+ if (containerManager == null) {
+ logger.error("ContainerManager is not accessible");
+ return;
+ }
+
+ String networkID = BaseHandler.convertNeutronIDToKey(id);
+ ContainerConfig config = new ContainerConfig();
+ config.setContainer(networkID);
+ containerManager.removeContainer(config);
+ }
+
}
package org.opendaylight.ovsdb.neutron.provider;
+import java.math.BigInteger;
import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
+import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
+import org.opendaylight.controller.sal.action.ActionType;
import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.ServiceHelper;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.sal.utils.StatusCode;
class OF10ProviderManager extends ProviderNetworkManager {
private static final Logger logger = LoggerFactory.getLogger(OF10ProviderManager.class);
+ Map<NodeVlan, FlowConfig> floodEntries = new HashMap<NodeVlan, FlowConfig>();
@Override
public boolean hasPerTenantTunneling() {
return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
}
} catch (Exception e) {
- logger.error(node+" is not Overlay ready");
+ logger.error(node+" is not Overlay ready due to exception", e);
return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
}
return new Status(StatusCode.SUCCESS);
}
+ /**
+ * Program OF1.0 Flow rules on br-tun on the ingress direction from the network towards the br-int.
+ * The logic is to simply match on the incoming tunnel OF-Port (which carries the TenantNetwork GRE-Key)
+ * and rewrite the Corresponding internal Vlan and pass it on to br-int via the patch port.
+ */
+ private void programLocalIngressTunnelBridgeRules(Node node, int tunnelOFPort, int internalVlan, int patchPort) {
+ String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
+ if (brIntId == null) {
+ logger.error("Failed to initialize Flow Rules for {}", node);
+ return;
+ }
+ try {
+ String flowName = "TepMatch"+tunnelOFPort+""+internalVlan;
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
+ Set<String> dpids = bridge.getDatapath_id();
+ if (dpids == null || dpids.size() == 0) return;
+ Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+ Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+ IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
+ IForwardingRulesManager.class, "default", this);
+ if (frm.getStaticFlow(flowName, ofNode) != null) {
+ logger.debug("Local Ingress Flow exists : {} for Flow {} on {} / {}", flowName, ofNode, node);
+ return;
+ }
+
+ FlowConfig flow = new FlowConfig();
+ flow.setName(flowName);
+ flow.setNode(ofNode);
+ flow.setPriority("100");
+ flow.setIngressPort(tunnelOFPort+"");
+ List<String> actions = new ArrayList<String>();
+ actions.add(ActionType.SET_VLAN_ID+"="+internalVlan);
+ actions.add(ActionType.OUTPUT.toString()+"="+patchPort);
+ flow.setActions(actions);
+ Status status = frm.addStaticFlow(flow);
+ logger.debug("Local Ingress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
+ } catch (Exception e) {
+ logger.error("Failed to initialize Flow Rules for {}", node, e);
+ }
+ }
+
+ /**
+ * Program OF1.0 Flow rules on br-tun on the remote Node on its egress direction towards the overlay network
+ * for a VM (with the attachedMac).
+ * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
+ * and output the traffic to the appropriate GRE Tunnel (which carries the GRE-Key for that Tenant Network).
+ * Also perform the Strip-Vlan action.
+ */
+ private void programRemoteEgressTunnelBridgeRules(Node node, int patchPort, String attachedMac,
+ int internalVlan, int tunnelOFPort) {
+ String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
+ if (brIntId == null) {
+ logger.error("Failed to initialize Flow Rules for {}", node);
+ return;
+ }
+ try {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
+ Set<String> dpids = bridge.getDatapath_id();
+ if (dpids == null || dpids.size() == 0) return;
+ Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+ Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+ String flowName = "TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac);
+ IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
+ IForwardingRulesManager.class, "default", this);
+ if (frm.getStaticFlow(flowName, ofNode) != null) {
+ logger.debug("Remove Egress Flow exists : {} for Flow {} on {} / {}", flowName, ofNode, node);
+ return;
+ }
+ FlowConfig flow = new FlowConfig();
+ flow.setName(flowName);
+ flow.setNode(ofNode);
+ flow.setPriority("100");
+ flow.setDstMac(attachedMac);
+ flow.setIngressPort(patchPort+"");
+ flow.setVlanId(internalVlan+"");
+ List<String> actions = new ArrayList<String>();
+ actions.add(ActionType.POP_VLAN.toString());
+ actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
+ flow.setActions(actions);
+ Status status = frm.addStaticFlow(flow);
+ logger.debug("Remote Egress Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
+ } catch (Exception e) {
+ logger.error("Failed to initialize Flow Rules for {}", node, e);
+ }
+ }
+
+ /**
+ * Program OF1.0 Flow rules to flood the broadcast & unknown-unicast traffic over br-tun on the egress direction
+ * towards the network on all the overlay tunnels that corresponds to the tenant network.
+ * The logic is to simply match on the incoming vlan, mac from the patch-port connected to br-int (patch-int)
+ * and output the traffic to all the GRE-Tunnels for this Tenant Network (which carries the GRE-Key).
+ * Also perform the Strip-Vlan action.
+ */
+ private void programFloodEgressTunnelBridgeRules(Node node, int patchPort, int internalVlan, int tunnelOFPort) {
+ String brIntId = InternalNetworkManager.getManager().getInternalBridgeUUID(node, AdminConfigManager.getManager().getTunnelBridgeName());
+ if (brIntId == null) {
+ logger.error("Failed to initialize Flow Rules for {}", node);
+ return;
+ }
+ try {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Bridge bridge = (Bridge) ovsdbTable.getRow(node, Bridge.NAME.getName(), brIntId);
+ Set<String> dpids = bridge.getDatapath_id();
+ if (dpids == null || dpids.size() == 0) return;
+ Long dpidLong = Long.valueOf(HexEncode.stringToLong((String)dpids.toArray()[0]));
+ Node ofNode = new Node(Node.NodeIDType.OPENFLOW, dpidLong);
+ NodeVlan nv = new NodeVlan(ofNode, internalVlan);
+ FlowConfig existingFlowConfig = floodEntries.get(nv);
+ IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
+ IForwardingRulesManager.class, "default", this);
+ FlowConfig flow = existingFlowConfig;
+ Status status = null;
+ if (flow == null) {
+ flow = new FlowConfig();
+ flow.setName("TepFlood"+internalVlan);
+ flow.setNode(ofNode);
+ flow.setPriority("1");
+ flow.setIngressPort(patchPort+"");
+ flow.setVlanId(internalVlan+"");
+ List<String> actions = new ArrayList<String>();
+ actions.add(ActionType.POP_VLAN.toString());
+ actions.add(ActionType.OUTPUT.toString()+"="+tunnelOFPort);
+ flow.setActions(actions);
+ status = frm.addStaticFlow(flow);
+ logger.debug("Add Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
+ status, flow, ofNode, node);
+ } else {
+ flow = new FlowConfig(existingFlowConfig);
+ List<String> actions = flow.getActions();
+ String outputPort = ActionType.OUTPUT.toString()+"="+tunnelOFPort;
+ if (actions != null && !actions.contains(outputPort)) {
+ actions.add(outputPort);
+ flow.setActions(actions);
+ } else {
+ return;
+ }
+ status = frm.modifyStaticFlow(flow);
+ logger.debug("Modify Flood Egress Flow Programming Status {} for Flow {} on {} / {}",
+ status, flow, ofNode, node);
+ }
+ if (status.isSuccess()) {
+ floodEntries.put(nv, flow);
+ }
+
+ } catch (Exception e) {
+ logger.error("Failed to initialize Flow Rules for {}", node, e);
+ }
+ }
+
+ private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
+ Interface intf, boolean local) {
+ String networkId = TenantNetworkManager.getManager().getNetworkIdForSegmentationId(segmentationId);
+ if (networkId == null) {
+ logger.debug("Tenant Network not found with Segmenation-id {}",segmentationId);
+ return;
+ }
+ int internalVlan = TenantNetworkManager.getManager().getInternalVlan(networkId);
+ if (internalVlan == 0) {
+ logger.debug("No InternalVlan provisioned for Tenant Network {}",networkId);
+ return;
+ }
+ Map<String, String> externalIds = intf.getExternal_ids();
+ if (externalIds == null) {
+ logger.error("No external_ids seen in {}", intf);
+ return;
+ }
+
+ String attachedMac = externalIds.get(TenantNetworkManager.EXTERNAL_ID_VM_MAC);
+ if (attachedMac == null) {
+ logger.error("No AttachedMac seen in {}", intf);
+ return;
+ }
+ String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
+
+ int patchOFPort = -1;
+ try {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ Map<String, Table<?>> intfs = ovsdbTable.getRows(node, Interface.NAME.getName());
+ if (intfs != null) {
+ for (Table<?> row : intfs.values()) {
+ Interface patchIntf = (Interface)row;
+ if (patchIntf.getName().equalsIgnoreCase(patchInt)) {
+ Set<BigInteger> of_ports = patchIntf.getOfport();
+ if (of_ports == null || of_ports.size() <= 0) {
+ logger.error("Could NOT Identified Patch port {} -> OF ({}) on {}", patchInt, node);
+ continue;
+ }
+ patchOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
+ logger.debug("Identified Patch port {} -> OF ({}) on {}", patchInt, patchOFPort, node);
+ break;
+ }
+ }
+ if (patchOFPort == -1) {
+ logger.error("Cannot identify {} interface on {}", patchInt, node);
+ }
+ for (Table<?> row : intfs.values()) {
+ Interface tunIntf = (Interface)row;
+ if (tunIntf.getName().equals(this.getTunnelName(tunnelType, segmentationId, dst))) {
+ Set<BigInteger> of_ports = tunIntf.getOfport();
+ if (of_ports == null || of_ports.size() <= 0) {
+ logger.error("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node);
+ continue;
+ }
+ int tunnelOFPort = Long.valueOf(((BigInteger)of_ports.toArray()[0]).longValue()).intValue();
+
+ if (tunnelOFPort == -1) {
+ logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
+ return;
+ }
+ logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
+
+ if (!local) {
+ programRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
+ }
+ programLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
+ programFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
+ return;
+ }
+ }
+ }
+ } catch (Exception e) {
+ logger.error("", e);
+ }
+ }
+
@Override
- public Status createTunnels(String tunnelType, String tunnelKey, Node srcNode) {
+ public Status createTunnels(String tunnelType, String tunnelKey, Node srcNode, Interface intf) {
Status status = getTunnelReadinessStatus(srcNode, tunnelKey);
if (!status.isSuccess()) return status;
if (!status.isSuccess()) continue;
InetAddress src = AdminConfigManager.getManager().getTunnelEndPoint(srcNode);
InetAddress dst = AdminConfigManager.getManager().getTunnelEndPoint(dstNode);
- addTunnelPort(srcNode, tunnelType, src, dst, tunnelKey);
+ status = addTunnelPort(srcNode, tunnelType, src, dst, tunnelKey);
+ if (status.isSuccess()) {
+ this.programTunnelRules(tunnelType, tunnelKey, dst, srcNode, intf, true);
+ }
addTunnelPort(dstNode, tunnelType, dst, src, tunnelKey);
+ if (status.isSuccess()) {
+ this.programTunnelRules(tunnelType, tunnelKey, src, dstNode, intf, false);
+ }
}
return new Status(StatusCode.SUCCESS);
}
+ private String getTunnelName(String tunnelType, String key, InetAddress dst) {
+ return tunnelType+"-"+key+"-"+dst.getHostAddress();
+ }
+
+ private Interface getTunnelInterface (Node node, String tunnelType, InetAddress dst, String key) {
+ try {
+ OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+ String portName = getTunnelName(tunnelType, key, dst);
+
+ Map<String, Table<?>> tunIntfs = ovsdbTable.getRows(node, Interface.NAME.getName());
+ if (tunIntfs != null) {
+ for (Table<?> row : tunIntfs.values()) {
+ Interface tunIntf = (Interface)row;
+ if (tunIntf.getName().equals(portName)) return tunIntf;
+ }
+
+ }
+ } catch (Exception e) {
+ logger.error("", e);
+ }
+ return null;
+ }
+
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);
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();
+ String portName = getTunnelName(tunnelType, key, dst);
if (this.isTunnelPresent(node, portName, bridgeUUID)) {
logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
List<Node> nodes = connectionService.getNodes();
for (Node srcNode : nodes) {
- this.createTunnels(tunnelType, tunnelKey, srcNode);
+ this.createTunnels(tunnelType, tunnelKey, srcNode, null);
+ }
+ return new Status(StatusCode.SUCCESS);
+ }
+
+ private class NodeVlan {
+ Node node;
+ int vlan;
+ public NodeVlan(Node node, int vlan) {
+ super();
+ this.node = node;
+ this.vlan = vlan;
+ }
+ public Node getNode() {
+ return node;
+ }
+ public int getVlan() {
+ return vlan;
+ }
+ @Override
+ public String toString() {
+ return "NodeVlan [node=" + node + ", vlan=" + vlan + "]";
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((node == null) ? 0 : node.hashCode());
+ result = prime * result + vlan;
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ NodeVlan other = (NodeVlan) obj;
+ if (node == null) {
+ if (other.node != null)
+ return false;
+ } else if (!node.equals(other.node))
+ return false;
+ if (vlan != other.vlan)
+ return false;
+ return true;
}
- return null;
}
}
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.ovsdb.lib.table.Interface;
class OF13ProviderManager extends ProviderNetworkManager {
}
@Override
- public Status createTunnels(String tunnelType, String tunnelKey, Node source) {
+ public Status createTunnels(String tunnelType, String tunnelKey, Node source, Interface intf) {
// TODO Auto-generated method stub
return null;
}
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.ovsdb.lib.table.Interface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract boolean hasPerTenantTunneling();
public abstract Status createTunnels(String tunnelType, String tunnelKey);
- public abstract Status createTunnels(String tunnelType, String tunnelKey, Node source);
+ public abstract Status createTunnels(String tunnelType, String tunnelKey, Node source, Interface intf);
}