diff --git a/src/vnsw/agent/cmn/agent.cc b/src/vnsw/agent/cmn/agent.cc index eefab072f24..fec86dd730d 100644 --- a/src/vnsw/agent/cmn/agent.cc +++ b/src/vnsw/agent/cmn/agent.cc @@ -132,6 +132,7 @@ void Agent::SetAgentTaskPolicy() { kTaskFlowKSync, kTaskFlowUpdate, kTaskFlowAudit, + kTaskFlowStatsUpdate, "Agent::Services", "Agent::StatsCollector", kTaskFlowStatsCollector, @@ -309,6 +310,11 @@ void Agent::SetAgentTaskPolicy() { SetTaskPolicyOne(kTaskDBExclude, db_exclude_task_exclude_list, sizeof(db_exclude_task_exclude_list) / sizeof(char *)); + const char *flow_stats_update_exclude_list[] = { + "Agent::Uve" + }; + SetTaskPolicyOne(kTaskFlowStatsUpdate, flow_stats_update_exclude_list, + sizeof(flow_stats_update_exclude_list) / sizeof(char *)); } void Agent::CreateLifetimeManager() { diff --git a/src/vnsw/agent/cmn/agent.h b/src/vnsw/agent/cmn/agent.h index 3a186a6d2ac..850ba1103e8 100644 --- a/src/vnsw/agent/cmn/agent.h +++ b/src/vnsw/agent/cmn/agent.h @@ -220,6 +220,7 @@ extern void RouterIdDepInit(Agent *agent); #define kTaskFlowKSync "Agent::FlowKSync" #define kTaskFlowAudit "KSync::FlowAudit" #define kTaskFlowStatsCollector "Flow::StatsCollector" +#define kTaskFlowStatsUpdate "Agent::FlowStatsUpdate" #define kTaskHealthCheck "Agent::HealthCheck" diff --git a/src/vnsw/agent/cmn/agent_stats.cc b/src/vnsw/agent/cmn/agent_stats.cc index cef34fd7563..8411dbeaac0 100644 --- a/src/vnsw/agent/cmn/agent_stats.cc +++ b/src/vnsw/agent/cmn/agent_stats.cc @@ -24,7 +24,7 @@ void AgentStats::Reset() { pkt_invalid_agent_hdr_ = pkt_invalid_interface_ = 0; pkt_no_handler_ = pkt_dropped_ = flow_created_ = 0; pkt_fragments_dropped_ = 0; - flow_aged_ = flow_active_ = flow_drop_due_to_max_limit_ = 0; + flow_aged_ = flow_drop_due_to_max_limit_ = 0; flow_drop_due_to_linklocal_limit_ = ipc_in_msgs_ = 0; ipc_out_msgs_ = in_tpkts_ = in_bytes_ = out_tpkts_ = 0; out_bytes_ = 0; @@ -112,86 +112,23 @@ void AgentStatsReq::HandleRequest() const { sandesh->Response(); } -void AgentStats::UpdateAddMinMaxStats(uint64_t count, uint64_t time) { - if ((max_flow_adds_per_second_ == kInvalidFlowCount) || - (count > max_flow_adds_per_second_)) { - max_flow_adds_per_second_ = count; +void AgentStats::UpdateFlowMinMaxStats(uint64_t total_flows, + FlowCounters &stat) const { + uint64_t count = total_flows - stat.prev_flow_count; + if ((stat.max_flows_per_second == kInvalidFlowCount) || + (count > stat.max_flows_per_second)) { + stat.max_flows_per_second = count; } - if ((min_flow_adds_per_second_ == kInvalidFlowCount) || - (count < min_flow_adds_per_second_)) { - min_flow_adds_per_second_ = count; + if ((stat.min_flows_per_second == kInvalidFlowCount) || + (count < stat.min_flows_per_second)) { + stat.min_flows_per_second = count; } - prev_flow_add_time_ = time; + stat.prev_flow_count = total_flows; } -void AgentStats::UpdateFlowAddMinMaxStats(uint64_t time) { - uint64_t diff_micro_secs = time - prev_flow_add_time_; - uint64_t diff_secs = 0; - uint64_t count = 0; - if (diff_micro_secs) { - diff_secs = diff_micro_secs/1000000; - } - if (!diff_secs) { - return; - } - if (diff_secs > 1) { - count = (flow_created_ - 1) - prev_flow_created_; - if (count) { - UpdateAddMinMaxStats(count, time); - prev_flow_created_ = flow_created_ - 1; - return; - } - } - count = flow_created_ - prev_flow_created_; - UpdateAddMinMaxStats(count, time); - prev_flow_created_ = flow_created_; -} - -void AgentStats::UpdateDelMinMaxStats(uint64_t count, uint64_t time) { - if ((max_flow_deletes_per_second_ == kInvalidFlowCount) || - (count > max_flow_deletes_per_second_)) { - max_flow_deletes_per_second_ = count; - } - if ((min_flow_deletes_per_second_ == kInvalidFlowCount) || - (count < min_flow_deletes_per_second_)) { - min_flow_deletes_per_second_ = count; - } - prev_flow_delete_time_ = time; -} - -void AgentStats::UpdateFlowDelMinMaxStats(uint64_t time) { - uint64_t diff_micro_secs = time - prev_flow_delete_time_; - uint64_t diff_secs = 0; - uint64_t count = 0; - if (diff_micro_secs) { - diff_secs = diff_micro_secs/1000000; - } - if (!diff_secs) { - return; - } - if (diff_secs > 1) { - count = (flow_aged_ - 1) - prev_flow_aged_; - if (count) { - prev_flow_aged_ = flow_aged_ - 1; - UpdateDelMinMaxStats(count, time); - return; - } - } - count = flow_aged_ - prev_flow_aged_; - UpdateDelMinMaxStats(count, time); - prev_flow_aged_ = flow_aged_; -} - -void AgentStats::ResetFlowAddMinMaxStats(uint64_t time) { - max_flow_adds_per_second_ = kInvalidFlowCount; - min_flow_adds_per_second_ = kInvalidFlowCount; - prev_flow_add_time_ = time; -} - -void AgentStats::ResetFlowDelMinMaxStats(uint64_t time) { - max_flow_deletes_per_second_ = kInvalidFlowCount; - min_flow_deletes_per_second_ = kInvalidFlowCount; - prev_flow_delete_time_ = time; +void AgentStats::ResetFlowMinMaxStats(FlowCounters &stat) const { + stat.max_flows_per_second = kInvalidFlowCount; + stat.min_flows_per_second = kInvalidFlowCount; } void AgentStats::RegisterFlowCountFn(FlowCountFn cb) { diff --git a/src/vnsw/agent/cmn/agent_stats.h b/src/vnsw/agent/cmn/agent_stats.h index 56b81906b5b..75571bc1ec3 100644 --- a/src/vnsw/agent/cmn/agent_stats.h +++ b/src/vnsw/agent/cmn/agent_stats.h @@ -13,7 +13,19 @@ typedef boost::function FlowCountFn; class AgentStats { public: - static const uint64_t kInvalidFlowCount = 0xFFFFFFFFFFFFFFFF; + static const uint32_t kInvalidFlowCount = 0xFFFFFFFF; + static const int kFlowStatsUpdateInterval = 1000; + struct FlowCounters { + uint64_t prev_flow_count; //previous flow created/aged count + uint32_t max_flows_per_second; //max_flows_added/deleted_per_second + uint32_t min_flows_per_second; //min_flows_added/deleted_per_second + + FlowCounters() : prev_flow_count(0), + max_flows_per_second(kInvalidFlowCount), + min_flows_per_second(kInvalidFlowCount) { + } + }; + AgentStats(Agent *agent) : agent_(agent), xmpp_reconnect_(), xmpp_in_msgs_(), xmpp_out_msgs_(), xmpp_config_in_msgs_(), sandesh_reconnects_(0U), @@ -22,18 +34,15 @@ class AgentStats { pkt_invalid_agent_hdr_(0U), pkt_invalid_interface_(0U), pkt_no_handler_(0U), pkt_fragments_dropped_(0U), pkt_dropped_(0U), max_flow_count_(0), - flow_created_(0U), flow_aged_(0U), flow_active_(0U), flow_drop_due_to_max_limit_(0), flow_drop_due_to_linklocal_limit_(0), - prev_flow_created_(0U), prev_flow_aged_(0U), - max_flow_adds_per_second_(kInvalidFlowCount), - min_flow_adds_per_second_(kInvalidFlowCount), - max_flow_deletes_per_second_(kInvalidFlowCount), - min_flow_deletes_per_second_(kInvalidFlowCount), + flow_stats_update_timeout_(kFlowStatsUpdateInterval), ipc_in_msgs_(0U), ipc_out_msgs_(0U), in_tpkts_(0U), in_bytes_(0U), out_tpkts_(0U), out_bytes_(0U) { assert(singleton_ == NULL); singleton_ = this; flow_count_ = 0; + flow_created_ = 0; + flow_aged_ = 0; } virtual ~AgentStats() {singleton_ = NULL;} @@ -71,7 +80,7 @@ class AgentStats { uint32_t sandesh_http_sessions() const {return sandesh_http_sessions_;} void incr_flow_created() { - flow_created_++; + flow_created_.fetch_and_increment(); uint32_t count = flow_count_.fetch_and_increment(); if (count > max_flow_count_) max_flow_count_ = count + 1; @@ -84,9 +93,17 @@ class AgentStats { uint64_t max_flow_count() const {return max_flow_count_;} - void incr_flow_aged() {flow_aged_++;} + void incr_flow_aged() { flow_aged_.fetch_and_increment(); } uint64_t flow_aged() const {return flow_aged_;} + int flow_stats_update_timeout() const { + return flow_stats_update_timeout_; + } + + void set_flow_stats_update_timeout(int value) { + flow_stats_update_timeout_ = value; + } + void incr_flow_drop_due_to_max_limit() {flow_drop_due_to_max_limit_++;} uint64_t flow_drop_due_to_max_limit() const { return flow_drop_due_to_max_limit_; @@ -134,53 +151,46 @@ class AgentStats { void incr_out_bytes(uint64_t count) {out_bytes_ += count;} uint64_t out_bytes() const {return out_bytes_;} - uint64_t max_flow_adds_per_second() const { - return max_flow_adds_per_second_; + uint32_t max_flow_adds_per_second() const { + return added_.max_flows_per_second; } - uint64_t min_flow_adds_per_second() const { - return min_flow_adds_per_second_; + uint32_t min_flow_adds_per_second() const { + return added_.min_flows_per_second; } - uint64_t max_flow_deletes_per_second() const { - return max_flow_deletes_per_second_; + uint32_t max_flow_deletes_per_second() const { + return deleted_.max_flows_per_second; } - uint64_t min_flow_deletes_per_second() const { - return min_flow_deletes_per_second_; + uint32_t min_flow_deletes_per_second() const { + return deleted_.min_flows_per_second; } - void set_prev_flow_add_time(uint64_t time) { - prev_flow_add_time_ = time; - } - void set_prev_flow_delete_time(uint64_t time) { - prev_flow_delete_time_ = time; - } void set_prev_flow_created(uint64_t value) { - prev_flow_created_ = value; + added_.prev_flow_count = value; } + void set_prev_flow_aged(uint64_t value) { - prev_flow_aged_ = value; + deleted_.prev_flow_count = value; } - void set_max_flow_adds_per_second(uint64_t value) { - max_flow_adds_per_second_ = value;; + void set_max_flow_adds_per_second(uint32_t value) { + added_.max_flows_per_second = value; } - void set_min_flow_adds_per_second(uint64_t value) { - min_flow_adds_per_second_ = value;; + void set_min_flow_adds_per_second(uint32_t value) { + added_.min_flows_per_second = value; } - void set_max_flow_deletes_per_second(uint64_t value) { - max_flow_deletes_per_second_ = value;; + void set_max_flow_deletes_per_second(uint32_t value) { + deleted_.max_flows_per_second = value; } - void set_min_flow_deletes_per_second(uint64_t value) { - min_flow_deletes_per_second_ = value; + void set_min_flow_deletes_per_second(uint32_t value) { + deleted_.min_flows_per_second = value; } - void UpdateFlowAddMinMaxStats(uint64_t time); - void UpdateFlowDelMinMaxStats(uint64_t time); - void ResetFlowAddMinMaxStats(uint64_t time); - void ResetFlowDelMinMaxStats(uint64_t time); + void UpdateFlowMinMaxStats(uint64_t total_flows, FlowCounters &stat) const; + void ResetFlowMinMaxStats(FlowCounters &stat) const; void RegisterFlowCountFn(FlowCountFn cb); uint32_t FlowCount() const; + FlowCounters& added() { return added_; } + FlowCounters& deleted() { return deleted_; } private: - void UpdateAddMinMaxStats(uint64_t count, uint64_t time); - void UpdateDelMinMaxStats(uint64_t count, uint64_t time); Agent *agent_; FlowCountFn flow_count_fn_; @@ -208,19 +218,13 @@ class AgentStats { // Flow stats tbb::atomic flow_count_; uint32_t max_flow_count_; - uint64_t flow_created_; - uint64_t flow_aged_; - uint64_t flow_active_; uint64_t flow_drop_due_to_max_limit_; uint64_t flow_drop_due_to_linklocal_limit_; - uint64_t prev_flow_created_; - uint64_t prev_flow_aged_; - uint64_t max_flow_adds_per_second_; - uint64_t min_flow_adds_per_second_; - uint64_t max_flow_deletes_per_second_; - uint64_t min_flow_deletes_per_second_; - uint64_t prev_flow_add_time_; - uint64_t prev_flow_delete_time_; + tbb::atomic flow_created_; + tbb::atomic flow_aged_; + FlowCounters added_; + FlowCounters deleted_; + int flow_stats_update_timeout_; // Kernel IPC uint64_t ipc_in_msgs_; diff --git a/src/vnsw/agent/pkt/flow_proto.cc b/src/vnsw/agent/pkt/flow_proto.cc index 8895cdcb581..c1335ad7a2f 100644 --- a/src/vnsw/agent/pkt/flow_proto.cc +++ b/src/vnsw/agent/pkt/flow_proto.cc @@ -26,7 +26,10 @@ FlowProto::FlowProto(Agent *agent, boost::asio::io_service &io) : flow_update_queue_(agent, this, &update_tokens_, agent->params()->flow_task_latency_limit(), 16), use_vrouter_hash_(false), ipv4_trace_filter_(), ipv6_trace_filter_(), - stats_() { + stats_(), + stats_update_timer_(TimerManager::CreateTimer + (*(agent->event_manager())->io_service(), "FlowStatsUpdateTimer", + TaskScheduler::GetInstance()->GetTaskId(kTaskFlowStatsUpdate), 0)) { linklocal_flow_count_ = 0; agent->SetFlowProto(this); set_trace(false); @@ -90,6 +93,8 @@ void FlowProto::InitDone() { for (uint16_t i = 0; i < flow_table_list_.size(); i++) { flow_table_list_[i]->InitDone(); } + stats_update_timer_->Start(agent_->stats()->flow_stats_update_timeout(), + boost::bind(&FlowProto::FlowStatsUpdate, this)); } void FlowProto::Shutdown() { @@ -103,6 +108,10 @@ void FlowProto::Shutdown() { flow_ksync_queue_[i]->Shutdown(); } flow_update_queue_.Shutdown(); + if (stats_update_timer_) { + stats_update_timer_->Cancel(); + TimerManager::DeleteTimer(stats_update_timer_); + } } static std::size_t HashCombine(std::size_t hash, uint64_t val) { @@ -838,3 +847,11 @@ void FlowProto::SetProfileData(ProfileData *data) { data->flow_.token_stats_.del_failures_ = del_tokens_.failures(); data->flow_.token_stats_.del_restarts_ = del_tokens_.restarts(); } + +bool FlowProto::FlowStatsUpdate() const { + agent_->stats()->UpdateFlowMinMaxStats(agent_->stats()->flow_created(), + agent_->stats()->added()); + agent_->stats()->UpdateFlowMinMaxStats(agent_->stats()->flow_aged(), + agent_->stats()->deleted()); + return true; +} diff --git a/src/vnsw/agent/pkt/flow_proto.h b/src/vnsw/agent/pkt/flow_proto.h index 489c64cffea..261f6043426 100644 --- a/src/vnsw/agent/pkt/flow_proto.h +++ b/src/vnsw/agent/pkt/flow_proto.h @@ -70,7 +70,6 @@ class FlowProto : public Proto { uint32_t FlowCount() const; void VnFlowCounters(const VnEntry *vn, uint32_t *in_count, uint32_t *out_count); - bool AddFlow(FlowEntry *flow); bool UpdateFlow(FlowEntry *flow); @@ -128,6 +127,7 @@ class FlowProto : public Proto { FlowTraceFilter *ipv6_trace_filter() { return &ipv6_trace_filter_; } bool ProcessFlowEvent(const FlowEvent &req, FlowTable *table); + bool FlowStatsUpdate() const; FlowTokenPool add_tokens_; FlowTokenPool ksync_tokens_; @@ -144,6 +144,7 @@ class FlowProto : public Proto { FlowTraceFilter ipv4_trace_filter_; FlowTraceFilter ipv6_trace_filter_; FlowStats stats_; + Timer *stats_update_timer_; }; extern SandeshTraceBufferPtr PktFlowTraceBuf; diff --git a/src/vnsw/agent/pkt/flow_table.cc b/src/vnsw/agent/pkt/flow_table.cc index 99583732a3b..d38c220471b 100644 --- a/src/vnsw/agent/pkt/flow_table.cc +++ b/src/vnsw/agent/pkt/flow_table.cc @@ -143,7 +143,6 @@ FlowEntry *FlowTable::Locate(FlowEntry *flow, uint64_t time) { ret = flow_entry_map_.insert(FlowEntryMapPair(flow->key(), flow)); if (ret.second == true) { agent_->stats()->incr_flow_created(); - agent_->stats()->UpdateFlowAddMinMaxStats(time); ret.first->second->set_on_tree(); return flow; } @@ -312,7 +311,6 @@ void FlowTable::DeleteInternal(FlowEntry *fe, uint64_t time, DeleteKSync(fe); agent_->stats()->incr_flow_aged(); - agent_->stats()->UpdateFlowDelMinMaxStats(time); } bool FlowTable::DeleteFlows(FlowEntry *flow, FlowEntry *rflow) { diff --git a/src/vnsw/agent/test/test_agent_init.cc b/src/vnsw/agent/test/test_agent_init.cc index 90e67b7ef08..a7730b7f80d 100644 --- a/src/vnsw/agent/test/test_agent_init.cc +++ b/src/vnsw/agent/test/test_agent_init.cc @@ -66,6 +66,8 @@ void TestAgentInit::FactoryInit() { // Optional modules or modules that have different implementation are created // by init module void TestAgentInit::CreateModules() { + /* Set timeout to high value so that it doesn't get fired */ + agent()->stats()->set_flow_stats_update_timeout(0x7FFFFFFF); ContrailInitCommon::CreateModules(); pkt0_.reset(new TestPkt0Interface(agent(), "pkt0", *agent()->event_manager()->io_service())); diff --git a/src/vnsw/agent/uve/stats_manager.cc b/src/vnsw/agent/uve/stats_manager.cc index 0c0c0250287..2b80dd0d3e8 100644 --- a/src/vnsw/agent/uve/stats_manager.cc +++ b/src/vnsw/agent/uve/stats_manager.cc @@ -13,7 +13,6 @@ StatsManager::StatsManager(Agent* agent) intf_listener_id_(DBTableBase::kInvalidId), agent_(agent), request_queue_(agent->task_scheduler()->GetTaskId("Agent::Uve"), 0, boost::bind(&StatsManager::RequestHandler, this, _1)) { - AddNamelessVrfStatsEntry(); } @@ -309,3 +308,66 @@ bool StatsManager::RequestHandler(boost::shared_ptr req) { } return true; } + +bool StatsManager::BuildFlowRate(AgentStats::FlowCounters &created, + AgentStats::FlowCounters &aged, + FlowRateComputeInfo &flow_info, + VrouterFlowRate &flow_rate) const { + uint64_t max_add_rate = 0, min_add_rate = 0; + uint64_t max_del_rate = 0, min_del_rate = 0; + uint64_t cur_time = UTCTimestampUsec(); + if (flow_info.prev_time_) { + uint64_t diff_time = cur_time - flow_info.prev_time_; + uint64_t diff_secs = diff_time / 1000000; + if (diff_secs) { + uint64_t created_flows = created.prev_flow_count - + flow_info.prev_flow_created_; + uint64_t aged_flows = aged.prev_flow_count - + flow_info.prev_flow_aged_; + //Flow setup/delete rate are always sent + if (created_flows) { + max_add_rate = created.max_flows_per_second; + min_add_rate = created.min_flows_per_second; + if (max_add_rate == AgentStats::kInvalidFlowCount) { + LOG(WARN, "Invalid max_flow_adds_per_second " << + max_add_rate); + max_add_rate = 0; + } + if (min_add_rate == AgentStats::kInvalidFlowCount) { + LOG(WARN, "Invalid min_flow_adds_per_second " << + min_add_rate); + min_add_rate = 0; + } + } + if (aged_flows) { + max_del_rate = aged.max_flows_per_second; + min_del_rate = aged.min_flows_per_second; + if (max_del_rate == AgentStats::kInvalidFlowCount) { + LOG(WARN, "Invalid max_flow_deletes_per_second " << + max_del_rate); + max_del_rate = 0; + } + if (min_del_rate == AgentStats::kInvalidFlowCount) { + LOG(WARN, "Invalid min_flow_deletes_per_second " << + min_del_rate); + min_del_rate = 0; + } + } + flow_rate.set_added_flows(created_flows); + flow_rate.set_max_flow_adds_per_second(max_add_rate); + flow_rate.set_min_flow_adds_per_second(min_add_rate); + flow_rate.set_deleted_flows(aged_flows); + flow_rate.set_max_flow_deletes_per_second(max_del_rate); + flow_rate.set_min_flow_deletes_per_second(min_del_rate); + agent_->stats()->ResetFlowMinMaxStats(created); + agent_->stats()->ResetFlowMinMaxStats(aged); + flow_info.prev_time_ = cur_time; + flow_info.prev_flow_created_ = created.prev_flow_count; + flow_info.prev_flow_aged_ = aged.prev_flow_count; + return true; + } + } else { + flow_info.prev_time_ = cur_time; + } + return false; +} diff --git a/src/vnsw/agent/uve/stats_manager.h b/src/vnsw/agent/uve/stats_manager.h index 6b15f95d997..30290e81660 100644 --- a/src/vnsw/agent/uve/stats_manager.h +++ b/src/vnsw/agent/uve/stats_manager.h @@ -6,6 +6,7 @@ #define _ROOT_STATS_MANAGER_H_ #include +#include #include #include #include @@ -14,6 +15,16 @@ #include #include +struct FlowRateComputeInfo { + uint64_t prev_time_; + uint64_t prev_flow_created_; + uint64_t prev_flow_aged_; + + FlowRateComputeInfo() : prev_time_(UTCTimestampUsec()), + prev_flow_created_(0), prev_flow_aged_(0) { + } +}; + // The container class for storing stats queried from vrouter // Defines routines for storing and managing (add, delete and query) // interface, vrf and drop statistics @@ -159,6 +170,10 @@ class StatsManager { void RegisterDBClients(); bool RequestHandler(boost::shared_ptr req); void EnqueueEvent(const boost::shared_ptr &req); + bool BuildFlowRate(AgentStats::FlowCounters &created, + AgentStats::FlowCounters &aged, + FlowRateComputeInfo &flow_info, + VrouterFlowRate &flow_rate) const; friend class AgentStatsCollectorTest; private: diff --git a/src/vnsw/agent/uve/test/test_vrouter_uve.cc b/src/vnsw/agent/uve/test/test_vrouter_uve.cc index b1ddeb0ed2e..4e773ee941e 100644 --- a/src/vnsw/agent/uve/test/test_vrouter_uve.cc +++ b/src/vnsw/agent/uve/test/test_vrouter_uve.cc @@ -1161,31 +1161,27 @@ TEST_F(UveVrouterUveTest, FlowSetupRate) { } }; - //Update prev_time to current_time - 1 sec - uint64_t t = UTCTimestampUsec() - 1000000; - vr->set_prev_flow_setup_rate_export_time(t); - agent_->stats()->set_prev_flow_add_time(t); - //Create Flows EXPECT_EQ(0, flow_proto_->FlowCount()); CreateFlow(flow, 2); EXPECT_EQ(4U, flow_proto_->FlowCount()); + //Update prev_time to current_time - 1 sec + uint64_t t = UTCTimestampUsec() - 1000000; + vr->set_prev_flow_setup_rate_export_time(t); + agent_->stats()->UpdateFlowMinMaxStats(agent_->stats()->flow_created(), + agent_->stats()->added()); + //Trigger framing and send of UVE message vr->SendVrouterMsg(); //Verify flow add rate const VrouterStatsAgent stats = vr->last_sent_stats(); EXPECT_EQ(4U, stats.get_flow_rate().get_added_flows()); - EXPECT_EQ(1U, stats.get_flow_rate().get_max_flow_adds_per_second()); - EXPECT_EQ(1U, stats.get_flow_rate().get_min_flow_adds_per_second()); + EXPECT_EQ(4U, stats.get_flow_rate().get_max_flow_adds_per_second()); + EXPECT_EQ(4U, stats.get_flow_rate().get_min_flow_adds_per_second()); EXPECT_EQ(0U, stats.get_flow_rate().get_deleted_flows()); - //Update prev_time to current_time - 1 sec - t = UTCTimestampUsec() - 1000000; - vr->set_prev_flow_setup_rate_export_time(t); - agent_->stats()->set_prev_flow_add_time(t); - //Create two more flows TestFlow flow2[] = { //Add a TCP forward and reverse flow @@ -1201,25 +1197,32 @@ TEST_F(UveVrouterUveTest, FlowSetupRate) { CreateFlow(flow2, 1); EXPECT_EQ(6U, flow_proto_->FlowCount()); + //Update prev_time to current_time - 1 sec + t = UTCTimestampUsec() - 1000000; + vr->set_prev_flow_setup_rate_export_time(t); + agent_->stats()->UpdateFlowMinMaxStats(agent_->stats()->flow_created(), + agent_->stats()->added()); + //Trigger framing and send of UVE message vr->SendVrouterMsg(); //Verify flow add rate const VrouterStatsAgent stats2 = vr->last_sent_stats(); EXPECT_EQ(2U, stats2.get_flow_rate().get_added_flows()); - EXPECT_EQ(4U, stats2.get_flow_rate().get_max_flow_adds_per_second()); - EXPECT_EQ(4U, stats2.get_flow_rate().get_min_flow_adds_per_second()); + EXPECT_EQ(2U, stats2.get_flow_rate().get_max_flow_adds_per_second()); + EXPECT_EQ(2U, stats2.get_flow_rate().get_min_flow_adds_per_second()); EXPECT_EQ(0U, stats2.get_flow_rate().get_deleted_flows()); - //Update prev_time to current_time - 1 sec - t = UTCTimestampUsec() - 1000000; - vr->set_prev_flow_setup_rate_export_time(t); - agent_->stats()->set_prev_flow_delete_time(t); - //Delete flows and verify delete rate DeleteFlow(flow2, 1); WAIT_FOR(1000, 1000, ((flow_proto_->FlowCount() == 4U))); + //Update prev_time to current_time - 1 sec + t = UTCTimestampUsec() - 1000000; + vr->set_prev_flow_setup_rate_export_time(t); + agent_->stats()->UpdateFlowMinMaxStats(agent_->stats()->flow_aged(), + agent_->stats()->deleted()); + //Trigger framing and send of UVE message vr->SendVrouterMsg(); @@ -1227,8 +1230,8 @@ TEST_F(UveVrouterUveTest, FlowSetupRate) { const VrouterStatsAgent stats3 = vr->last_sent_stats(); EXPECT_EQ(0U, stats3.get_flow_rate().get_added_flows()); EXPECT_EQ(2U, stats3.get_flow_rate().get_deleted_flows()); - EXPECT_EQ(1U, stats3.get_flow_rate().get_max_flow_deletes_per_second()); - EXPECT_EQ(1U, stats3.get_flow_rate().get_min_flow_deletes_per_second()); + EXPECT_EQ(2U, stats3.get_flow_rate().get_max_flow_deletes_per_second()); + EXPECT_EQ(2U, stats3.get_flow_rate().get_min_flow_deletes_per_second()); FlowTearDown(); vr->clear_count(); diff --git a/src/vnsw/agent/uve/test/vrouter_uve_entry_test.cc b/src/vnsw/agent/uve/test/vrouter_uve_entry_test.cc index cc0b8061559..69153a479be 100644 --- a/src/vnsw/agent/uve/test/vrouter_uve_entry_test.cc +++ b/src/vnsw/agent/uve/test/vrouter_uve_entry_test.cc @@ -87,5 +87,5 @@ void VrouterUveEntryTest::WaitForWalkCompletion() { void VrouterUveEntryTest::set_prev_flow_setup_rate_export_time(uint64_t micro_secs) { - prev_flow_setup_rate_export_time_ = micro_secs; + flow_info_.prev_time_ = micro_secs; } diff --git a/src/vnsw/agent/uve/test/vrouter_uve_entry_test.h b/src/vnsw/agent/uve/test/vrouter_uve_entry_test.h index 6bcd3716acb..25451376497 100644 --- a/src/vnsw/agent/uve/test/vrouter_uve_entry_test.h +++ b/src/vnsw/agent/uve/test/vrouter_uve_entry_test.h @@ -49,8 +49,12 @@ class VrouterUveEntryTest : public VrouterUveEntry { void DispatchComputeCpuStateMsg(const ComputeCpuState &ccs); void WaitForWalkCompletion(); void set_prev_flow_setup_rate_export_time(uint64_t micro_secs); - void set_prev_flow_created(uint64_t count) { prev_flow_created_ = count; } - void set_prev_flow_aged(uint64_t count) { prev_flow_aged_ = count; } + void set_prev_flow_created(uint64_t count) { + flow_info_.prev_flow_created_ = count; + } + void set_prev_flow_aged(uint64_t count) { + flow_info_.prev_flow_aged_ = count; + } private: bool first_uve_dispatched_; uint32_t vrouter_msg_count_; diff --git a/src/vnsw/agent/uve/vrouter_uve_entry.cc b/src/vnsw/agent/uve/vrouter_uve_entry.cc index 71bd3381918..8a55302c2ae 100644 --- a/src/vnsw/agent/uve/vrouter_uve_entry.cc +++ b/src/vnsw/agent/uve/vrouter_uve_entry.cc @@ -25,8 +25,7 @@ using namespace std; VrouterUveEntry::VrouterUveEntry(Agent *agent) : VrouterUveEntryBase(agent), bandwidth_count_(0), port_bitmap_(), - prev_flow_setup_rate_export_time_(0), prev_flow_created_(0), - prev_flow_aged_(0) { + flow_info_() { start_time_ = UTCTimestampUsec(); } @@ -35,8 +34,6 @@ VrouterUveEntry::~VrouterUveEntry() { bool VrouterUveEntry::SendVrouterMsg() { static bool first = true; - uint64_t max_add_rate = 0, min_add_rate = 0; - uint64_t max_del_rate = 0, min_del_rate = 0; bool change = false; VrouterStatsAgent stats; @@ -232,43 +229,15 @@ bool VrouterUveEntry::SendVrouterMsg() { if (first) { stats.set_uptime(start_time_); } - uint64_t cur_time = UTCTimestampUsec(); - if (prev_flow_setup_rate_export_time_) { - uint64_t diff_time = cur_time - prev_flow_setup_rate_export_time_; - uint64_t created_flows = agent_->stats()->flow_created() - - prev_flow_created_; - uint64_t aged_flows = agent_->stats()->flow_aged() - prev_flow_aged_; - uint64_t diff_secs = diff_time / 1000000; - if (diff_secs) { - //Flow setup/delete rate are always sent - if (created_flows) { - max_add_rate = agent_->stats()->max_flow_adds_per_second(); - min_add_rate = agent_->stats()->min_flow_adds_per_second(); - } - if (aged_flows) { - max_del_rate = agent_->stats()->max_flow_deletes_per_second(); - min_del_rate = agent_->stats()->min_flow_deletes_per_second(); - } - - VrouterFlowRate flow_rate; - flow_rate.set_added_flows(created_flows); - flow_rate.set_max_flow_adds_per_second(max_add_rate); - flow_rate.set_min_flow_adds_per_second(min_add_rate); - flow_rate.set_deleted_flows(aged_flows); - flow_rate.set_max_flow_deletes_per_second(max_del_rate); - flow_rate.set_min_flow_deletes_per_second(min_del_rate); - flow_rate.set_active_flows(agent_->pkt()->get_flow_proto()-> - FlowCount()); - stats.set_flow_rate(flow_rate); - change = true; - agent_->stats()->ResetFlowAddMinMaxStats(cur_time); - agent_->stats()->ResetFlowDelMinMaxStats(cur_time); - prev_flow_setup_rate_export_time_ = cur_time; - prev_flow_created_ = agent_->stats()->flow_created(); - prev_flow_aged_ = agent_->stats()->flow_aged(); - } - } else { - prev_flow_setup_rate_export_time_ = cur_time; + AgentStats::FlowCounters &added = agent_->stats()->added(); + AgentStats::FlowCounters &deleted = agent_->stats()->deleted(); + uint32_t active_flows = agent_->pkt()->get_flow_proto()->FlowCount(); + VrouterFlowRate flow_rate; + bool built = uve->stats_manager()->BuildFlowRate(added, deleted, flow_info_, + flow_rate); + if (built) { + flow_rate.set_active_flows(active_flows); + stats.set_flow_rate(flow_rate); } AgentIFMapStats ifmap_stats; @@ -388,6 +357,7 @@ bool VrouterUveEntry::BuildPhysicalInterfaceList(vector &list) PhysicalInterfaceSet::const_iterator it = phy_intf_set_.begin(); while (it != phy_intf_set_.end()) { const Interface *intf = *it; + ++it; AgentUveStats *uve = static_cast(agent_->uve()); StatsManager::InterfaceStats *s = uve->stats_manager()->GetInterfaceStats(intf); @@ -404,7 +374,6 @@ bool VrouterUveEntry::BuildPhysicalInterfaceList(vector &list) phy_stat_entry.set_duplexity(s->duplexity); list.push_back(phy_stat_entry); changed = true; - ++it; } return changed; } @@ -462,6 +431,7 @@ void VrouterUveEntry::InitPrevStats() const { PhysicalInterfaceSet::const_iterator it = phy_intf_set_.begin(); while (it != phy_intf_set_.end()) { const Interface *intf = *it; + ++it; AgentUveStats *uve = static_cast(agent_->uve()); StatsManager::InterfaceStats *s = uve->stats_manager()->GetInterfaceStats(intf); @@ -474,7 +444,6 @@ void VrouterUveEntry::InitPrevStats() const { s->prev_out_bytes = s->out_bytes; s->prev_5min_out_bytes = s->out_bytes; s->prev_10min_out_bytes = s->out_bytes; - ++it; } } diff --git a/src/vnsw/agent/uve/vrouter_uve_entry.h b/src/vnsw/agent/uve/vrouter_uve_entry.h index 49d4cf491d1..fd40860bac9 100644 --- a/src/vnsw/agent/uve/vrouter_uve_entry.h +++ b/src/vnsw/agent/uve/vrouter_uve_entry.h @@ -6,7 +6,7 @@ #define vnsw_agent_vrouter_uve_entry_h #include -#include +#include //The class that defines data-structures to store VRouter information //required for sending VRouter UVE. @@ -22,9 +22,7 @@ class VrouterUveEntry : public VrouterUveEntryBase { protected: uint8_t bandwidth_count_; L4PortBitmap port_bitmap_; - uint64_t prev_flow_setup_rate_export_time_; - uint64_t prev_flow_created_; - uint64_t prev_flow_aged_; + FlowRateComputeInfo flow_info_; private: void InitPrevStats() const; void FetchDropStats(AgentDropStats &ds) const;