/*
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P. 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 com.google.gson.Gson;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.nic.neutron.NeutronSecurityRule;
import org.opendaylight.nic.of.renderer.model.IntentEndPointType;
import org.opendaylight.nic.of.renderer.model.PortFlow;
import org.opendaylight.nic.of.renderer.utils.IntentFlowUtils;
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.yang.types.rev130715.MacAddress;
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.FlowCookie;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
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.Constraints;
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.Log;
import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.constraints.constraints.ClassificationConstraint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.Intent;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.security.InvalidParameterException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
public class IntentFlowManager extends AbstractFlowManager {
private List<String> endPointGroups = null;
private Action action = null;
private static final Logger LOG = LoggerFactory.getLogger(IntentFlowManager.class);
private FlowStatisticsListener flowStatisticsListener;
private Intent intent;
private String flowName = "";
private static final int RADIX = 10;
private static final String CONSTRAINTS_NOT_FOUND_EXCEPTION = "Constraints not found! ";
public void setEndPointGroups(List<String> endPointGroups) {
this.endPointGroups = endPointGroups;
}
public void setAction(Action action) {
this.action = action;
}
public void setIntent(Intent intent) {
this.intent = intent;
}
IntentFlowManager(DataBroker dataBroker, PipelineManager pipelineManager) {
super(dataBroker, pipelineManager);
flowStatisticsListener = new FlowStatisticsListener(dataBroker);
}
@Override
public void pushFlow(final NodeId nodeId, final FlowAction flowAction) {
IntentFlowUtils.validate(endPointGroups);
IntentFlowUtils.validate(flowAction);
final IntentEndPointType endPointType = IntentFlowUtils.extractEndPointType(endPointGroups);
switch (endPointType) {
case MAC_ADDRESS_BASED:
final MacAddress srcMacAddress = IntentFlowUtils.extractSrcMacAddress(endPointGroups);
final MacAddress dstMacAddress = IntentFlowUtils.extractDstMacAddress(endPointGroups);
pushFlowsByMacAddress(srcMacAddress, dstMacAddress, nodeId, flowAction);
break;
case PORT_BASED:
pushFlowsByPortNumber(nodeId, flowAction);
break;
case UNKNOWN:
String actionClass = action.getClass().getName();
LOG.error("Invalid action: {}", actionClass);
break;
}
}
private void pushFlowsByMacAddress(final MacAddress srcMacAddress, final MacAddress dstMacAddress,
final NodeId nodeId, final FlowAction flowAction) {
final MatchBuilder matchBuilder = MatchUtils.createEthMatch(new MatchBuilder(), srcMacAddress, dstMacAddress);
final String flowIdStr = srcMacAddress.getValue() + "_" + dstMacAddress.getValue();
final FlowBuilder flowBuilder = createFlowBuilder(matchBuilder, new FlowId(flowIdStr));
// TODO: Extend for other actions
if (action instanceof Allow) {
// Set allow action
Instructions buildedInstructions = createOutputInstructions(OutputPortValues.NORMAL);
flowBuilder.setInstructions(buildedInstructions);
} else if (action instanceof Log) {
// Logs the statistics data and return.
String flowIdName = readDataTransaction(nodeId, flowBuilder);
if (flowIdName != null) {
flowStatisticsListener.registerFlowStatisticsListener(dataBroker, nodeId, flowIdName);
}
} else {
String actionClass = action.getClass().getName();
LOG.error("Invalid action: {}", actionClass);
}
writeDataTransaction(nodeId, flowBuilder, flowAction);
}
private void pushFlowsByPortNumber(final NodeId nodeId, final FlowAction flowAction) {
for (Constraints cons : intent.getConstraints()) {
/**
* Code block for security rules flow matches
*/
if(cons.getConstraints() instanceof ClassificationConstraint) {
ClassificationConstraint portConstraint = (ClassificationConstraint) cons.getConstraints();
pushPortFlows(portConstraint, nodeId, flowAction);
}
}
}
private void pushPortFlows(final ClassificationConstraint portConstraint,
final NodeId nodeId,
final FlowAction flowAction) {
String portObject = "";
try {
portObject = portConstraint.getClassificationConstraint().getClassifier();
} catch (NullPointerException npe) {
throw new InvalidParameterException(CONSTRAINTS_NOT_FOUND_EXCEPTION + npe.getMessage());
}
Gson gson = new Gson();
final NeutronSecurityRule securityRule = gson.fromJson(portObject, NeutronSecurityRule.class);
final PortFlow portFlow = IntentFlowUtils.extractPortFlow(securityRule, endPointGroups);
final Set<MatchBuilder> matchBuilders = portFlow.createPortRangeMatchBuilder();
for(MatchBuilder matchBuilder : matchBuilders) {
final String flowIdStr = intent.getId().toString();
final FlowBuilder flowBuilder = createFlowBuilder(matchBuilder, new FlowId(flowIdStr));
final Instructions builtInstructions = createOutputInstructions(OutputPortValues.NORMAL);
flowBuilder.setInstructions(builtInstructions);
flowName = portFlow.getFlowName(intent.getId().getValue());
writeDataTransaction(nodeId, flowBuilder, flowAction);
}
}
private FlowBuilder createFlowBuilder(final MatchBuilder matchBuilder, final FlowId flowId) {
final Match match = matchBuilder.build();
final FlowKey key = new FlowKey(flowId);
final FlowBuilder flowBuilder = new FlowBuilder();
final BigInteger cookieId = new BigInteger("20", RADIX);
flowBuilder.setId(flowId);
flowBuilder.setKey(key);
flowBuilder.setFlowName(flowName);
flowBuilder.setCookie(new FlowCookie(cookieId));
flowBuilder.setCookieMask(new FlowCookie(cookieId));
flowBuilder.setContainerName(null);
flowBuilder.setStrict(false);
flowBuilder.setMatch(match);
flowBuilder.setFlags(new FlowModFlags(false, false, false, false, false));
flowBuilder.setBarrier(true);
flowBuilder.setPriority(OFRendererConstants.DEFAULT_PRIORITY);
flowBuilder.setHardTimeout(OFRendererConstants.DEFAULT_HARD_TIMEOUT);
flowBuilder.setIdleTimeout(OFRendererConstants.DEFAULT_IDLE_TIMEOUT);
return flowBuilder;
}
@Deprecated
@Override
protected String createFlowName() {
StringBuilder sb = new StringBuilder();
sb.append(OFRendererConstants.INTENT_L2_FLOW_NAME);
sb.append(endPointGroups.get(OFRendererConstants.SRC_END_POINT_GROUP_INDEX));
sb.append(endPointGroups.get(OFRendererConstants.DST_END_POINT_GROUP_INDEX));
sb.append(intent.getId().getValue());
return sb.toString();
}
}