/*
* Copyright (c) 2015 Inocybe Technologies and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.nic.of.renderer.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.nic.of.renderer.utils.MatchUtils;
import org.opendaylight.nic.pipeline_manager.PipelineManager;
import org.opendaylight.nic.utils.FlowAction;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Instructions;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.Allow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.Block;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MplsIntentFlowManager extends AbstractFlowManager {
private List<String> endPointGroups = null;
private Map<String, Map<String, String>> subjectsMapping = null;
private Action action = null;
private static final Logger LOG = LoggerFactory.getLogger(MplsIntentFlowManager.class);
public MplsIntentFlowManager(DataBroker dataBroker, PipelineManager pipelineManager) {
super(dataBroker, pipelineManager);
}
public void setEndPointGroups(List<String> endPointGroups) {
this.endPointGroups = endPointGroups;
}
public void setAction(Action action) {
this.action = action;
}
public void setSubjectsMapping(Map<String, Map<String, String>> subjectsMapping) {
this.subjectsMapping = subjectsMapping;
}
@Override
public void pushFlow(NodeId nodeId, FlowAction flowAction) {
// TODO Auto-generated method stub
}
/**
* Create a IP Prefix Match and push MPLS label on switch
* @param nodeId :NodeID of the switch on which the push MPLS label should be performed
* @param flowAction :Add flow action
* @param outputPort :Port to which packet should be sent to after pushing label
*/
public void pushMplsFlow(NodeId nodeId, FlowAction flowAction, String outputPort) {
if (endPointGroups == null || action == null) {
LOG.error("Endpoints and action cannot be null");
return;
}
LOG.info("pushMPLSFlow on Node: {}", nodeId.getValue());
MatchBuilder matchBuilder = new MatchBuilder();
String endPointSrc = endPointGroups.get(OFRendererConstants.SRC_END_POINT_GROUP_INDEX);
String endPointDst = endPointGroups.get(OFRendererConstants.DST_END_POINT_GROUP_INDEX);
Ipv4Prefix srcPrefix = null;
Ipv4Prefix dstPrefix = null;
String label = null;
try {
srcPrefix = new Ipv4Prefix(subjectsMapping.get(endPointSrc).get(OFRendererConstants.IP_PREFIX_KEY));
dstPrefix = new Ipv4Prefix(subjectsMapping.get(endPointDst).get(OFRendererConstants.IP_PREFIX_KEY));
label = subjectsMapping.get(endPointDst).get(OFRendererConstants.MPLS_LABEL_KEY);
} catch (Exception e) {
LOG.error("Subject does not have mapping information for pushing MPLS label", e);
}
// Create IPv4 Prefix match
MatchUtils.createIPv4PrefixMatch(srcPrefix, dstPrefix, matchBuilder);
List<Long> labels = new ArrayList<>();
labels.add(new Long(label));
// Create Flow
FlowBuilder flowBuilder = createFlowBuilder(matchBuilder);
if (action instanceof Allow) {
//bos field is set to 1 since we only use one MPLS label
Short bos = 1;
Instructions buildedInstructions = null;
if(flowAction.equals(FlowAction.ADD_FLOW)) {
buildedInstructions = createMPLSIntentInstructions(labels, false, bos, outputPort, false);
LOG.info("Push MPLS label: {}", label, " to switch: {}", nodeId);
} else if (flowAction.equals(FlowAction.REMOVE_FLOW)) {
buildedInstructions = createClearFlowsInstructions();
LOG.info("Remove Push MPLS label flow: {}", label, " from switch: {}", nodeId);
}
flowBuilder.setInstructions(buildedInstructions);
} else if (action instanceof Block) {
LOG.warn("For Block Action the Instructions are not set");
} else {
LOG.error("Invalid action: {}", action.getClass().getName());
return;
}
writeDataTransaction(nodeId, flowBuilder, flowAction);
}
/**
* Create a MPLS Label Match and pop MPLS label on switch
* @param nodeId :NodeID of the switch on which the pop MPLS label should be performed
* @param flowAction :Add flow action
* @param outputPort :Port to which packet should be sent to after popping label
*/
public void popMplsFlow(NodeId nodeId, FlowAction flowAction, String outputPort) {
if (endPointGroups == null || action == null) {
LOG.error("Endpoints and action cannot be null");
return;
}
LOG.info("popMplsFlow on Node {} and output on port {}", nodeId.getValue(), outputPort);
String endPointDst = endPointGroups.get(OFRendererConstants.DST_END_POINT_GROUP_INDEX);
String label = null;
String serverMACAddress = null;
try {
Map<String, String> value = subjectsMapping.get(endPointDst);
label = value.get(OFRendererConstants.MPLS_LABEL_KEY);
serverMACAddress = value.get(OFRendererConstants.SERVER_DESTINATION_MAC_ADDRESS);
} catch (Exception e) {
LOG.error("Subject does not have mapping information for popping MPLS label", e);
}
List<Long> labels = new ArrayList<>();
labels.add(new Long(label));
MatchBuilder matchBuilder = MatchUtils.createMplsLabelBosMatch(new Long(label), true);
// Create Flow
FlowBuilder flowBuilder = createFlowBuilder(matchBuilder);
if (action instanceof Allow) {
//bos field is set to 1 since we only use one MPLS label
Short bos = 1;
Instructions builtInstructions = null;
if(flowAction.equals(FlowAction.ADD_FLOW)) {
builtInstructions = createMPLSIntentInstructions(labels, true, bos, outputPort, false, serverMACAddress);
LOG.info("Pop MPLS label at switch: {}", nodeId.getValue());
} else if (flowAction.equals(FlowAction.REMOVE_FLOW)) {
builtInstructions = createClearFlowsInstructions();
LOG.info("Remove Pop MPLS label flow: {}", label, " from switch: {}", nodeId);
}
flowBuilder.setInstructions(builtInstructions);
writeDataTransaction(nodeId, flowBuilder, flowAction);
} else if (action instanceof Block) {
LOG.warn("For Block Action the Instructions are not set");
} else {
LOG.error("Invalid action: {}", action.getClass().getName());
return;
}
}
/**
* Create a MPLS label Match and forward the packet on switch
* @param nodeId :NodeID of the switch on which the forward MPLS packet should be performed
* @param flowAction :Add flow action
* @param outputPort :Port to which packet should be forwarded
*/
public void forwardMplsFlow(NodeId nodeId, FlowAction flowAction, String outputPort) {
if (endPointGroups == null || action == null) {
LOG.error("Endpoints and action cannot be null");
return;
}
LOG.info("forwardMplsFlow on Node: {}", nodeId.getValue());
String endPointDst = endPointGroups.get(OFRendererConstants.DST_END_POINT_GROUP_INDEX);
String label = null;
try {
label = subjectsMapping.get(endPointDst).get(OFRendererConstants.MPLS_LABEL_KEY);
} catch (Exception e) {
LOG.error("Subject does not have mapping information for forwarding MPLS packets", e);
}
// Create MPLS label match
MatchBuilder matchBuilder = MatchUtils.createMplsLabelBosMatch(new Long(label), true);
// Create Flow
FlowBuilder flowBuilder = createFlowBuilder(matchBuilder);
if (action instanceof Allow) {
Instructions buildedInstructions = null;
if(flowAction.equals(FlowAction.ADD_FLOW)) {
buildedInstructions = createMPLSIntentInstructions(null, false, null, outputPort, true);
LOG.info("Forward MPLS label at switch: {}", nodeId);
} else if (flowAction.equals(FlowAction.REMOVE_FLOW)) {
buildedInstructions = createClearFlowsInstructions();
LOG.info("Remove forward MPLS label flow: {}", label, " from switch: {}", nodeId);
}
flowBuilder.setInstructions(buildedInstructions);
} else if (action instanceof Block) {
LOG.warn("For Block Action the Instructions are not set");
} else {
LOG.error("Invalid action: {}", action.getClass().getName());
return;
}
writeDataTransaction(nodeId, flowBuilder, flowAction);
}
private FlowBuilder createFlowBuilder(MatchBuilder matchBuilder) {
final Match match = matchBuilder.build();
// Flow named for convenience and uniqueness
String flowName = createFlowName();
final FlowId flowId = new FlowId(flowName);
final FlowKey key = new FlowKey(flowId);
final FlowBuilder flowBuilder = new FlowBuilder();
flowBuilder.setMatch(match);
flowBuilder.setId(flowId);
flowBuilder.setKey(key);
flowBuilder.setBarrier(true);
flowBuilder.setPriority(OFRendererConstants.DEFAULT_PRIORITY);
flowBuilder.setFlowName(flowName);
flowBuilder.setHardTimeout(OFRendererConstants.DEFAULT_HARD_TIMEOUT);
flowBuilder.setIdleTimeout(OFRendererConstants.DEFAULT_IDLE_TIMEOUT);
return flowBuilder;
}
@Override
protected String createFlowName() {
StringBuilder sb = new StringBuilder(OFRendererConstants.INTENT_MPLS_FLOW_NAME);
sb.append(endPointGroups.get(OFRendererConstants.SRC_END_POINT_GROUP_INDEX));
sb.append(endPointGroups.get(OFRendererConstants.DST_END_POINT_GROUP_INDEX));
return sb.toString();
}
}