/*
* Copyright (c) 2016 Cisco Systems, Inc. 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.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache;
import java.util.List;
import java.util.Objects;
import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition;
import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCache.FlowCacheBuilder;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCacheDefinition.FlowCacheDefinitionBuilder;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.util.FlowCacheCons;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.util.IidSflowNameUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.has.classifiers.Classifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FlowCacheFactory {
private static final Logger LOG = LoggerFactory.getLogger(FlowCacheFactory.class);
public static FlowCache createFlowCache(InstanceIdentifier<Classifier> classifierIid, Classifier classifier,
FlowCacheCons.Value value) {
FlowCacheDefinition flowCacheDefinition = createFlowCacheDefinition(classifier, value);
if (flowCacheDefinition == null) {
LOG.info("Cannot create flow cache for statistics of classifier {}\n{}", classifierIid, classifier);
return null;
}
return new FlowCacheBuilder().setDefinition(flowCacheDefinition)
.setName(IidSflowNameUtil.createFlowCacheName(classifierIid, value))
.setDirection(classifier.getDirection())
.build();
}
public static FlowCacheDefinition createFlowCacheDefinition(Classifier classifier,
FlowCacheCons.Value value) {
FlowCacheDefinitionBuilder fcdBuilder = new FlowCacheDefinitionBuilder();
if (L4ClassifierDefinition.ID.equals(classifier.getClassifierDefinitionId())) {
addEthTypeInfoToFlowCache(classifier, fcdBuilder);
if (!addIpProtoInfoToFlowCache(classifier, fcdBuilder)) {
return null;
}
if (!addL4InfoToFlowCache(classifier, fcdBuilder)) {
return null;
}
} else if (IpProtoClassifierDefinition.ID.equals(classifier.getClassifierDefinitionId())) {
addEthTypeInfoToFlowCache(classifier, fcdBuilder);
if (!addIpProtoInfoToFlowCache(classifier, fcdBuilder)) {
return null;
}
} else if (EtherTypeClassifierDefinition.ID.equals(classifier.getClassifierDefinitionId())) {
addEthTypeInfoToFlowCache(classifier, fcdBuilder);
} else {
LOG.warn("Sflow stats will not be pulled because of unknown classifier: {}", classifier);
return null;
}
fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.IP_SOURCE.get()).addValue(FlowCacheCons.Key.IP_DESTINATION.get());
fcdBuilder.setValue(value.get());
return fcdBuilder.build();
}
private static void addEthTypeInfoToFlowCache(Classifier classifier, FlowCacheDefinitionBuilder fcdBuilder) {
List<ParameterValue> parametersAndValues = classifier.getParameterValue();
ParameterValue ethTypeParam = getParamVal(parametersAndValues, EtherTypeClassifierDefinition.ETHERTYPE_PARAM);
if (ethTypeParam != null) {
fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.ETH_PROTOCOL.get());
fcdBuilder.getFilterBuilder()
.addValue(FlowCacheCons.Key.ETH_PROTOCOL.get() + FlowCacheCons.EQ + ethTypeParam.getIntValue());
} else {
fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.ETH_PROTOCOL.get());
fcdBuilder.getFilterBuilder()
.addValue(FlowCacheCons.Key.ETH_PROTOCOL.get() + FlowCacheCons.EQ + FlowUtils.IPv4 + FlowCacheCons.OR
+ FlowCacheCons.Key.ETH_PROTOCOL.get() + FlowCacheCons.EQ + FlowUtils.IPv6);
}
}
private static boolean addIpProtoInfoToFlowCache(Classifier classifier, FlowCacheDefinitionBuilder fcdBuilder) {
List<ParameterValue> parametersAndValues = classifier.getParameterValue();
ParameterValue ipProtoParam = getParamVal(parametersAndValues, IpProtoClassifierDefinition.PROTO_PARAM);
if (ipProtoParam != null) {
fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.IP_PROTOCOL.get());
fcdBuilder.getFilterBuilder()
.addValue(FlowCacheCons.Key.IP_PROTOCOL.get() + FlowCacheCons.EQ + ipProtoParam.getIntValue());
return true;
} else {
LOG.trace("Cannot add ip-proto information to flow cache for Sflow-RT.");
return false;
}
}
private static boolean addL4InfoToFlowCache(Classifier classifier, FlowCacheDefinitionBuilder fcdBuilder) {
List<ParameterValue> parametersAndValues = classifier.getParameterValue();
ParameterValue ipProtoParam = getParamVal(parametersAndValues, IpProtoClassifierDefinition.PROTO_PARAM);
ParameterValue dstPortParam = getParamVal(parametersAndValues, L4ClassifierDefinition.DST_PORT_PARAM);
ParameterValue srcPortParam = getParamVal(parametersAndValues, L4ClassifierDefinition.SRC_PORT_PARAM);
if (ipProtoParam == null || (dstPortParam == null && srcPortParam == null)) {
LOG.trace(
"Cannot add L4 information to flow cache for Sflow-RT."
+ "\nipProtoParam:{} dstPortParam:{} srcPortParam:{}",
ipProtoParam, dstPortParam, srcPortParam);
return false;
}
if (dstPortParam != null) {
if (!addTcpUdpPortKeys(ipProtoParam.getIntValue(), dstPortParam.getIntValue(), true, fcdBuilder)) {
return false;
}
}
if (srcPortParam != null) {
if (!addTcpUdpPortKeys(ipProtoParam.getIntValue(), srcPortParam.getIntValue(), false, fcdBuilder)) {
return false;
}
}
return true;
}
private static ParameterValue getParamVal(List<ParameterValue> parametersAndValues, String paramName) {
for (ParameterValue paramVal : parametersAndValues) {
if (paramName.equals(paramVal.getName().getValue())) {
return paramVal;
}
}
return null;
}
private static boolean addTcpUdpPortKeys(Long ipProto, Long port, boolean isDstPort,
FlowCacheDefinitionBuilder fcdBuilder) {
if (isDstPort) {
if (Objects.equals(ipProto, IpProtoClassifierDefinition.TCP_VALUE)) {
fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.TCP_DST_PORT.get());
fcdBuilder.getFilterBuilder().addValue(FlowCacheCons.Key.TCP_DST_PORT.get() + FlowCacheCons.EQ + port);
} else if (Objects.equals(ipProto, IpProtoClassifierDefinition.UDP_VALUE)) {
fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.UDP_DST_PORT.get());
fcdBuilder.getFilterBuilder().addValue(FlowCacheCons.Key.UDP_DST_PORT.get() + FlowCacheCons.EQ + port);
} else {
LOG.info("Statistics cannot be collected for ip-proto {} and port {}", ipProto, port);
return false;
}
} else {
if (Objects.equals(ipProto, IpProtoClassifierDefinition.TCP_VALUE)) {
fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.TCP_SRC_PORT.get());
fcdBuilder.getFilterBuilder().addValue(FlowCacheCons.Key.TCP_SRC_PORT.get() + FlowCacheCons.EQ + port);
} else if (Objects.equals(ipProto, IpProtoClassifierDefinition.UDP_VALUE)) {
fcdBuilder.getKeysBuilder().addValue(FlowCacheCons.Key.UDP_SRC_PORT.get());
fcdBuilder.getFilterBuilder().addValue(FlowCacheCons.Key.UDP_SRC_PORT.get() + FlowCacheCons.EQ + port);
} else {
LOG.info("Statistics cannot be collected for ip-proto {} and port {}", ipProto, port);
return false;
}
}
return true;
}
}