X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fstatistics-manager%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fstatistics%2Fmanager%2FFlowStatsTracker.java;h=e92d0bd6251dbf89af9c98b175aa699d8d697994;hp=06d6e821122617aa1642e3cfd6a5d46808f8518a;hb=3bad057a3d83945a7e23113aacbdba6ba9cb5d97;hpb=027bc8f87341f432654c3aaa7771658c25d2ca7d diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java index 06d6e82112..e92d0bd625 100644 --- a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java +++ b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java @@ -7,14 +7,20 @@ */ package org.opendaylight.controller.md.statistics.manager; +import java.math.BigInteger; import java.util.Collection; +import java.util.Collections; import java.util.Map.Entry; import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCookieMapping; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMap; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; @@ -29,68 +35,57 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.O import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Optional; + final class FlowStatsTracker extends AbstractListeningStatsTracker { - private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class); + private static final Logger LOG = LoggerFactory.getLogger(FlowStatsTracker.class); + private static final String ALIEN_SYSTEM_FLOW_ID = "#UF$TABLE*"; private final OpendaylightFlowStatisticsService flowStatsService; private FlowTableStatsTracker flowTableStats; private int unaccountedFlowsCounter = 1; - FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context) { + + FlowStatsTracker(final OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context) { super(context); this.flowStatsService = flowStatsService; } - FlowStatsTracker(OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, FlowTableStatsTracker flowTableStats) { + FlowStatsTracker(final OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context, final FlowTableStatsTracker flowTableStats) { this(flowStatsService, context); this.flowTableStats = flowTableStats; } @Override - protected void cleanupSingleStat(DataModificationTransaction trans, FlowStatsEntry item) { - InstanceIdentifier flowRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(item.getTableId())) - .child(Flow.class,item.getFlow().getKey()) - .augmentation(FlowStatisticsData.class).toInstance(); + protected void cleanupSingleStat(final DataModificationTransaction trans, final FlowStatsEntry item) { + KeyedInstanceIdentifier flowRef = getNodeIdentifier() + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(item.getTableId())) + .child(Flow.class, item.getFlow().getKey()); trans.removeOperationalData(flowRef); } @Override - protected FlowStatsEntry updateSingleStat(DataModificationTransaction trans, FlowAndStatisticsMapList map) { + protected FlowStatsEntry updateSingleStat(final DataModificationTransaction trans, final FlowAndStatisticsMapList map) { short tableId = map.getTableId(); - FlowBuilder flowBuilder = new FlowBuilder(); - FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder(); - FlowBuilder flow = new FlowBuilder(); - flow.setContainerName(map.getContainerName()); - flow.setBufferId(map.getBufferId()); - flow.setCookie(map.getCookie()); - flow.setCookieMask(map.getCookieMask()); - flow.setFlags(map.getFlags()); - flow.setFlowName(map.getFlowName()); - flow.setHardTimeout(map.getHardTimeout()); - if(map.getFlowId() != null) - flow.setId(new FlowId(map.getFlowId().getValue())); - flow.setIdleTimeout(map.getIdleTimeout()); - flow.setInstallHw(map.isInstallHw()); - flow.setInstructions(map.getInstructions()); - if(map.getFlowId()!= null) - flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue()))); - flow.setMatch(map.getMatch()); - flow.setOutGroup(map.getOutGroup()); - flow.setOutPort(map.getOutPort()); - flow.setPriority(map.getPriority()); - flow.setStrict(map.isStrict()); - flow.setTableId(tableId); - - Flow flowRule = flow.build(); + FlowBuilder flowBuilder = new FlowBuilder(map); + if (map.getFlowId() != null) { + flowBuilder.setId(new FlowId(map.getFlowId().getValue())); + } + if (map.getFlowId() != null) { + flowBuilder.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue()))); + } + + Flow flowRule = flowBuilder.build(); FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder(); stats.setByteCount(map.getByteCount()); @@ -105,96 +100,47 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker tableRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance(); - - //TODO: Not a good way to do it, need to figure out better way. - //TODO: major issue in any alternate approach is that flow key is incrementally assigned - //to the flows stored in data store. - // Augment same statistics to all the matching masked flow - Table table= (Table)trans.readConfigurationData(tableRef); - if(table != null){ - for(Flow existingFlow : table.getFlow()){ - logger.debug("Existing flow in data store : {}",existingFlow.toString()); - if(FlowComparator.flowEquals(flowRule,existingFlow)){ - InstanceIdentifier flowRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flowBuilder.setKey(existingFlow.getKey()); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Found matching flow in the datastore, augmenting statistics"); - // Update entry with timestamp of latest response - flow.setKey(existingFlow.getKey()); - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); - trans.putOperationalData(flowRef, flowBuilder.build()); - return flowStatsEntry; - } + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)).toInstance(); + + final FlowCookie flowCookie = flowRule.getCookie() != null + ? flowRule.getCookie() : new FlowCookie(BigInteger.ZERO); + final InstanceIdentifier flowCookieRef = tableRef + .augmentation(FlowCookieMapping.class) + .child(FlowCookieMap.class, new FlowCookieMapKey(flowCookie)); + + FlowCookieMap cookieMap = (FlowCookieMap) trans.readOperationalData(flowCookieRef); + + /* find flowKey in FlowCookieMap from DataStore/OPERATIONAL */ + Optional flowKey = this.getExistFlowKey(flowRule, tableRef, trans, cookieMap); + if ( ! flowKey.isPresent()) { + /* DataStore/CONFIG For every first statistic needs to be created */ + flowKey = this.getFlowKeyFromExistFlow(flowRule, tableRef, trans); + if ( ! flowKey.isPresent()) { + /* Alien flow */ + flowKey = this.makeAlienFlowKey(flowRule); } + cookieMap = applyNewFlowKey(cookieMap, flowKey, flowCookie); + trans.putOperationalData(flowCookieRef, cookieMap); } - table = (Table)trans.readOperationalData(tableRef); - if(table != null){ - for(Flow existingFlow : table.getFlow()){ - FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class); - if(augmentedflowStatisticsData != null){ - FlowBuilder existingOperationalFlow = new FlowBuilder(); - existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics()); - logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString()); - if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){ - InstanceIdentifier flowRef = getNodeIdentifierBuilder() - .augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,existingFlow.getKey()).toInstance(); - flowBuilder.setKey(existingFlow.getKey()); - flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics"); - // Update entry with timestamp of latest response - flow.setKey(existingFlow.getKey()); - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); - trans.putOperationalData(flowRef, flowBuilder.build()); - return flowStatsEntry; - } - } - } - } - - String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter); - this.unaccountedFlowsCounter++; - FlowKey newFlowKey = new FlowKey(new FlowId(flowKey)); - InstanceIdentifier flowRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class) - .child(Table.class, new TableKey(tableId)) - .child(Flow.class,newFlowKey).toInstance(); - flowBuilder.setKey(newFlowKey); + InstanceIdentifier flowRef = getNodeIdentifierBuilder() + .augmentation(FlowCapableNode.class) + .child(Table.class, new TableKey(tableId)) + .child(Flow.class, flowKey.get()).toInstance(); + flowBuilder.setKey(flowKey.get()); flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build()); - logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow", - flowBuilder.build()); // Update entry with timestamp of latest response - flow.setKey(newFlowKey); - FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build()); + flowBuilder.setKey(flowKey.get()); + FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId, flowBuilder.build()); trans.putOperationalData(flowRef, flowBuilder.build()); return flowStatsEntry; } @@ -214,14 +160,14 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker tables = flowTableStats.getTables(); - logger.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size()); + LOG.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size()); for (final TableKey key : tables) { - logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef()); + LOG.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef()); this.requestAggregateFlows(key); } this.requestAllFlowsAllTables(); - + } public void requestAllFlowsAllTables() { if (flowStatsService != null) { @@ -254,14 +200,14 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker, DataObject> change) { + public void onDataChanged(final DataChangeEvent, DataObject> change) { for (Entry, DataObject> e : change.getCreatedConfigurationData().entrySet()) { if (Flow.class.equals(e.getKey().getTargetType())) { final Flow flow = (Flow) e.getValue(); - logger.debug("Key {} triggered request for flow {}", e.getKey(), flow); + LOG.debug("Key {} triggered request for flow {}", e.getKey(), flow); requestFlow(flow); } else { - logger.debug("Ignoring key {}", e.getKey()); + LOG.debug("Ignoring key {}", e.getKey()); } } @@ -270,11 +216,8 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker flow = (InstanceIdentifier)key; - final InstanceIdentifier del = InstanceIdentifier.builder(flow) - .augmentation(FlowStatisticsData.class).build(); - logger.debug("Key {} triggered remove of augmentation {}", key, del); - - trans.removeOperationalData(del); + LOG.debug("Key {} triggered remove of Flow from operational space.", key); + trans.removeOperationalData(flow); } } trans.commit(); @@ -283,10 +226,79 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker getExistFlowKey(final Flow flowRule, final InstanceIdentifier tableRef, + final DataModificationTransaction trans, final FlowCookieMap cookieMap) { + + if (cookieMap != null) { + for (FlowId flowId : cookieMap.getFlowIds()) { + InstanceIdentifier flowIdent = tableRef.child(Flow.class, new FlowKey(flowId)); + if (flowId.getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) { + LOG.debug("Search for flow in the operational datastore by flowID: {} ", flowIdent); + Flow readedFlow = (Flow) trans.readOperationalData(flowIdent); + if (FlowComparator.flowEquals(flowRule, readedFlow)) { + return Optional. of(new FlowKey(flowId)); + } + } else { + LOG.debug("Search for flow in the configuration datastore by flowID: {} ", flowIdent); + Flow readedFlow = (Flow) trans.readConfigurationData(flowIdent); + if (FlowComparator.flowEquals(flowRule, readedFlow)) { + return Optional. of(new FlowKey(flowId)); + } + } + } + LOG.debug("Flow was not found in the datastore. Flow {} ", flowRule); + } + return Optional.absent(); + } + + /* Returns FlowKey from existing Flow in DataStore/CONFIGURATIONAL which is identified by cookie + * and by switch flow identification (priority and match) */ + private Optional getFlowKeyFromExistFlow(final Flow flowRule, final InstanceIdentifier
tableRef, + final DataModificationTransaction trans) { + + /* Try to find it in DataSotre/CONFIG */ + Table table= (Table)trans.readConfigurationData(tableRef); + if(table != null) { + for(Flow existingFlow : table.getFlow()) { + LOG.debug("Existing flow in data store : {}",existingFlow.toString()); + if(FlowComparator.flowEquals(flowRule,existingFlow)){ + return Optional. of(new FlowKey(existingFlow.getId())); + } + } + } + return Optional.absent(); + } + + /* Returns FlowKey which doesn't exist in any DataStore for now */ + private Optional makeAlienFlowKey(final Flow flowRule) { + + StringBuilder sBuilder = new StringBuilder(ALIEN_SYSTEM_FLOW_ID) + .append(flowRule.getTableId()).append("-").append(this.unaccountedFlowsCounter); + this.unaccountedFlowsCounter++; + final FlowId flowId = new FlowId(sBuilder.toString()); + return Optional. of(new FlowKey(flowId)); + } + + /* Build new whole FlowCookieMap or add new flowKey */ + private FlowCookieMap applyNewFlowKey(FlowCookieMap flowCookieMap, final Optional flowKey, + final FlowCookie flowCookie) { + if (flowCookieMap != null) { + flowCookieMap.getFlowIds().add(flowKey.get().getId()); + } else { + final FlowCookieMapBuilder flowCookieMapBuilder = new FlowCookieMapBuilder(); + flowCookieMapBuilder.setCookie(flowCookie); + flowCookieMapBuilder.setFlowIds(Collections.singletonList(flowKey.get().getId())); + flowCookieMap = flowCookieMapBuilder.build(); + } + return flowCookieMap; + } }