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;
}
}
- this.initializeFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
+ this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getTunnelBridgeName());
+ this.initializeOFNormalFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
+ this.initializeLLDPFlowRules(node, AdminConfigManager.getManager().getIntegrationBridgeName());
}
- private void initializeFlowRules(Node node, String bridgeName) {
+ 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);
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(ActionType.HW_PATH.toString());
+ normalAction.add(flowName);
flow.setActions(normalAction);
Status status = frm.addStaticFlow(flow);
logger.debug("Flow Programming Status {} for Flow {} on {} / {}", status, flow, ofNode, node);
}
}
+ 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) {
IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
List<Node> nodes = connectionService.getNodes();
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;
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);
}
- private void programLocalIngressTunnelBridgeRules(Node node, int tunnelOFPort, String attachedMac,
- int internalVlan, int patchPort) {
+ /**
+ * 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();
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("TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac));
+ flow.setName(flowName);
flow.setNode(ofNode);
flow.setPriority("100");
- flow.setDstMac(attachedMac);
flow.setIngressPort(tunnelOFPort+"");
List<String> actions = new ArrayList<String>();
actions.add(ActionType.SET_VLAN_ID+"="+internalVlan);
}
}
+ /**
+ * 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 (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("TepMatch"+tunnelOFPort+""+internalVlan+""+HexEncode.stringToLong(attachedMac));
+ flow.setName(flowName);
flow.setNode(ofNode);
flow.setPriority("100");
flow.setDstMac(attachedMac);
}
}
+ /**
+ * 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);
logger.error("No AttachedMac seen in {}", intf);
return;
}
- String patchInt = "";
- if (local) {
- patchInt = AdminConfigManager.getManager().getPatchToIntegration();
- } else {
- patchInt = AdminConfigManager.getManager().getPatchToTunnel();
- }
+ String patchInt = AdminConfigManager.getManager().getPatchToIntegration();
int patchOFPort = -1;
try {
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 Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), node);
+ 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) {
- programLocalIngressTunnelBridgeRules(node, tunnelOFPort, attachedMac, internalVlan, patchOFPort);
- } else {
+ if (!local) {
programRemoteEgressTunnelBridgeRules(node, patchOFPort, attachedMac, internalVlan, tunnelOFPort);
}
+ programLocalIngressTunnelBridgeRules(node, tunnelOFPort, internalVlan, patchOFPort);
+ programFloodEgressTunnelBridgeRules(node, patchOFPort, internalVlan, tunnelOFPort);
return;
}
}
logger.error("", e);
}
}
+
@Override
public Status createTunnels(String tunnelType, String tunnelKey, Node srcNode, Interface intf) {
Status status = getTunnelReadinessStatus(srcNode, tunnelKey);
return new Status(StatusCode.SUCCESS);
}
-
private String getTunnelName(String tunnelType, String key, InetAddress dst) {
return tunnelType+"-"+key+"-"+dst.getHostAddress();
}
}
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;
+ }
+ }
}