/*
* 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;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
import org.opendaylight.groupbasedpolicy.api.StatisticsManager;
import org.opendaylight.groupbasedpolicy.dto.ConsEpgKey;
import org.opendaylight.groupbasedpolicy.dto.EpgKey;
import org.opendaylight.groupbasedpolicy.dto.EpgKeyDto;
import org.opendaylight.groupbasedpolicy.dto.ProvEpgKey;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCache;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.flowcache.FlowCacheData;
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.common.rev140421.ContractId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.StatRecords;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.StatRecordsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.EpToEpStatistic;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.EpToEpStatisticBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.ep.to.ep.statistic.EpEpgToEpEpgStatistic;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.ep.to.ep.statistic.EpEpgToEpEpgStatisticBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.statistics.rev151215.statistic.records.stat.records.ep.to.ep.statistic.ep.epg.to.ep.epg.statistic.MatchedRuleStatisticBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableList;
public class ProcessDataTask implements Runnable {
private static final Logger LOG = LoggerFactory.getLogger(ProcessDataTask.class);
private FlowCache flowCache;
private BigInteger timestamp;
private StatisticsManager statisticsManager;
List<FlowCacheData> dataList;
public ProcessDataTask(FlowCache flowCache, List<FlowCacheData> dataList, BigInteger timestamp,
StatisticsManager statisticsManager) {
this.flowCache = flowCache;
this.dataList = dataList;
this.timestamp = timestamp;
this.statisticsManager = statisticsManager;
}
@Override
public void run() {
for (FlowCacheData flowCacheData : dataList) {
Map<String, String> flowCacheDataMap = createFlowCacheDataMap(flowCacheData);
if (flowCacheDataMap == null) {
LOG.info("Stats are skipped for {}", flowCacheData);
continue;
}
String srcIp = flowCacheDataMap.get(FlowCacheCons.Key.IP_SOURCE.get());
String dstIp = flowCacheDataMap.get(FlowCacheCons.Key.IP_DESTINATION.get());
EndpointL3 srcEpL3 = OFStatisticsManager.getEndpointL3ForIp(srcIp);
EndpointL3 dstEpL3 = OFStatisticsManager.getEndpointL3ForIp(dstIp);
if (srcEpL3 != null && dstEpL3 != null) {
ContractId contractId = IidSflowNameUtil.resolveContractIdFromFlowCacheName(flowCache.getName());
MatchedRuleStatisticBuilder matchedRuleStatisticBuilder = new MatchedRuleStatisticBuilder()
.setContract(contractId)
.setSubject(IidSflowNameUtil.resolveSubjectNameFromFlowCacheName(flowCache.getName()))
.setMatchedRule(IidSflowNameUtil.resolveRuleNameFromFlowCacheName(flowCache.getName()))
.setClassifier(ImmutableList
.of(IidSflowNameUtil.resolveClassifierNameFromFlowCacheName(flowCache.getName())));
if (FlowCacheCons.Value.BYTES.get().equals(IidSflowNameUtil.resolveFlowCacheValue(flowCache.getName()))) {
matchedRuleStatisticBuilder.setByteCount(Math.round(flowCacheData.getValue()));
} else if (FlowCacheCons.Value.FRAMES.get().equals(IidSflowNameUtil.resolveFlowCacheValue(flowCache.getName()))) {
matchedRuleStatisticBuilder.setPacketCount(Math.round(flowCacheData.getValue()));
}
Set<Pair<ConsEpgKey, ProvEpgKey>> epgsForContract = OFStatisticsManager.getEpgsForContract(contractId);
Set<EpgKey> epgsFromSrcEp = getEpgsFromEndpoint(srcEpL3);
Set<EpgKey> epgsFromDstEp = getEpgsFromEndpoint(dstEpL3);
Pair<? extends EpgKey, ? extends EpgKey> leftSrcEpgRightDstEpg = getMatchingEpgs(epgsForContract, epgsFromSrcEp, epgsFromDstEp, flowCache.getDirection());
if (leftSrcEpgRightDstEpg == null) {
LOG.info("Stats are skipped for {}", flowCacheData);
continue;
}
EpEpgToEpEpgStatistic epEpgToEpEpgStats = new EpEpgToEpEpgStatisticBuilder()
.setSrcEpg(leftSrcEpgRightDstEpg.getLeft().getEpgId())
.setDstEpg(leftSrcEpgRightDstEpg.getRight().getEpgId())
.setMatchedRuleStatistic(ImmutableList.of(matchedRuleStatisticBuilder.build()))
.build();
EpToEpStatistic e2e = new EpToEpStatisticBuilder().setSrcL2c(srcEpL3.getL2Context())
.setSrcMacAddress(srcEpL3.getMacAddress())
.setSrcTenant(srcEpL3.getTenant())
.setDstL2c(dstEpL3.getL2Context())
.setDstMacAddress(dstEpL3.getMacAddress())
.setDstTenant(dstEpL3.getTenant())
.setEpEpgToEpEpgStatistic(ImmutableList.of(epEpgToEpEpgStats))
.setTimestamp(timestamp)
.build();
StatRecords statRecords = new StatRecordsBuilder().setEpToEpStatistic(ImmutableList.of(e2e)).build();
if (LOG.isTraceEnabled()) {
LOG.trace("[sflow] writing StatRecords: {}", statRecords);
}
statisticsManager.writeStat(statRecords);
}
}
}
private Set<EpgKey> getEpgsFromEndpoint(EndpointL3 epL3) {
Set<EpgKey> result = new HashSet<>();
TenantId tenantId = epL3.getTenant();
if (epL3.getEndpointGroup() != null) {
result.add(new EpgKeyDto(epL3.getEndpointGroup(), tenantId));
}
List<EndpointGroupId> epgs = epL3.getEndpointGroups();
if (epgs != null) {
for (EndpointGroupId epg : epgs) {
result.add(new EpgKeyDto(epg, tenantId));
}
}
return result;
}
private Pair<? extends EpgKey, ? extends EpgKey> getMatchingEpgs(Set<Pair<ConsEpgKey, ProvEpgKey>> epgsForContract,
Set<EpgKey> epgsFromSrcEp, Set<EpgKey> epgsFromDstEp, Direction direction) {
if (direction == null || Direction.Bidirectional == direction) {
LOG.info("The bidirectional direction is not supported.");
return null;
}
for (Pair<ConsEpgKey, ProvEpgKey> epgForContract : epgsForContract) {
ConsEpgKey consEpg = epgForContract.getLeft();
ProvEpgKey provEpg = epgForContract.getRight();
if (epgsFromSrcEp.contains(consEpg) && epgsFromDstEp.contains(provEpg)) {
if (Direction.In.equals(direction)) {
return Pair.of(consEpg, provEpg);
} else if (Direction.Out.equals(direction)) {
return Pair.of(provEpg, consEpg);
}
}
if (epgsFromSrcEp.contains(provEpg) && epgsFromDstEp.contains(consEpg)) {
if (Direction.In.equals(direction)) {
return Pair.of(consEpg, provEpg);
} else if (Direction.Out.equals(direction)) {
return Pair.of(provEpg, consEpg);
}
}
}
LOG.info(
"EPGs of srcEP and dstEp does not match against EPGs for contract:"
+ "\nsrcEP EPGs: {}\ndstEP EPGs: {}\nEPGs for contract: {}",
epgsFromSrcEp, epgsFromDstEp, epgsForContract);
return null;
}
private Map<String, String> createFlowCacheDataMap(FlowCacheData flowCacheData) {
String[] splitValues = flowCacheData.getKey().split(",");
if (splitValues.length != flowCache.getKeyNum()) {
LOG.error(
"Key names and key values lists length do not match: {} != {}. Not processing.",
flowCache.getKeyNum(), splitValues.length);
return null;
}
Map<String, String> flowCacheDataMap = new HashMap<>();
for (int i = 0; i < flowCache.getKeyNum(); i++) {
flowCacheDataMap.put(flowCache.getKeyNames()[i], splitValues[i]);
}
return flowCacheDataMap;
}
}