From 30c2da3f700a870040862634c279f4265a84f0f8 Mon Sep 17 00:00:00 2001 From: Ravi BK Date: Wed, 4 May 2016 13:29:24 +0530 Subject: [PATCH] Issue: Requirement of DBTable and TaskStats counters for Introspect in R2.22.x Fix: Added support for DBTable and TaskStats counters in release R2.22.x. Added support for FlowStats as well. Change-Id: Ib6fcb9c5a08365922c81d0c9c3cd25ac233c4e55 closes-bug: #1528175 --- src/vnsw/agent/cmn/agent.h | 13 + src/vnsw/agent/oper/SConscript | 1 + src/vnsw/agent/oper/agent_profile.cc | 336 +++++++++++++++++++--- src/vnsw/agent/oper/agent_profile.h | 108 ++++++- src/vnsw/agent/oper/agent_profile.sandesh | 80 ++++++ src/vnsw/agent/oper/operdb_init.cc | 2 +- src/vnsw/agent/oper/operdb_init.h | 1 + src/vnsw/agent/pkt/flow_table.cc | 52 +++- src/vnsw/agent/pkt/flow_table.h | 24 ++ 9 files changed, 573 insertions(+), 44 deletions(-) create mode 100644 src/vnsw/agent/oper/agent_profile.sandesh diff --git a/src/vnsw/agent/cmn/agent.h b/src/vnsw/agent/cmn/agent.h index 483e3622ecb..7331e60500a 100644 --- a/src/vnsw/agent/cmn/agent.h +++ b/src/vnsw/agent/cmn/agent.h @@ -201,6 +201,19 @@ extern void RouterIdDepInit(Agent *agent); #define VROUTER_SERVER_PORT 20914 +#define kInterfaceDbTablePrefix "db.interface" +#define kVnDbTablePrefix "db.vn" +#define kVmDbTablePrefix "db.vm" +#define kVrfDbTablePrefix "db.vrf.0" +#define kLoadBalnceDbTablePrefix "db.loadbalancer.0" +#define kMplsDbTablePrefix "db.mpls" +#define kAclDbTablePrefix "db.acl" +#define kV4UnicastRouteDbTableSuffix "uc.route.0" +#define kV6UnicastRouteDbTableSuffix "uc.route6.0" +#define kL2RouteDbTableSuffix "l2.route.0" +#define kMcastRouteDbTableSuffix "mc.route.0" +#define kEvpnRouteDbTableSuffix "evpn.route.0" + class Agent { public: static const uint32_t kDefaultMaxLinkLocalOpenFds = 2048; diff --git a/src/vnsw/agent/oper/SConscript b/src/vnsw/agent/oper/SConscript index 3ac931870e6..584f7cd6eaa 100644 --- a/src/vnsw/agent/oper/SConscript +++ b/src/vnsw/agent/oper/SConscript @@ -15,6 +15,7 @@ if '-fno-exceptions' in cflags: except_env.Replace(CCFLAGS=cflags) SandeshGenFiles = env.SandeshGenCpp('agent.sandesh') +SandeshGenFiles += env.SandeshGenCpp('agent_profile.sandesh') SandeshGenFiles += env.SandeshGenCpp('multicast.sandesh') SandeshGenSrcs = env.ExtractCpp(SandeshGenFiles) sandesh_objs = AgentEnv.BuildExceptionCppObj(env, SandeshGenSrcs) diff --git a/src/vnsw/agent/oper/agent_profile.cc b/src/vnsw/agent/oper/agent_profile.cc index 0b97d4c7164..d3812cd7746 100644 --- a/src/vnsw/agent/oper/agent_profile.cc +++ b/src/vnsw/agent/oper/agent_profile.cc @@ -3,18 +3,25 @@ */ #include +#include +#include #include #include -#include +#include +#include +#include #include #include #include #include #include -#include +#include #include +#include +#include "db/db.h" + using namespace std; AgentProfile::AgentProfile(Agent *agent, bool enable) : @@ -36,6 +43,11 @@ AgentProfile::~AgentProfile() { } bool AgentProfile::TimerRun() { + ProfileData *data = GetLastProfileData(); + data->Get(agent_); + if (pkt_flow_stats_cb_.empty() == false) { + pkt_flow_stats_cb_(data); + } Log(); return true; } @@ -43,48 +55,290 @@ bool AgentProfile::TimerRun() { string GetProfileString(DBTable *table, const char *name) { stringstream str; str << setw(16) << name - << " Size " << setw(8) << table->Size() - << " Enqueue " << setw(8) << table->enqueue_count() - << " Input " << setw(8) << table->input_count() - << " Notify " << setw(8) << table->notify_count(); + << " Size " << setw(6) << table->Size() + << " Enqueue " << setw(6) << table->enqueue_count() + << " Input " << setw(6) << table->input_count() + << " Notify " << setw(6) << table->notify_count(); return str.str(); } -string GetInterfaceProfileString(InterfaceTable *table, const char *name) { - stringstream str; - str << setw(4) << " LI " << setw(6) << table->li_count() - << " VMI " << table->vmi_count() << " / " - << setw(6) << table->active_vmi_count() << " / " - << setw(6) << table->vmi_ifnode_to_req() << " / " - << setw(6) << table->li_ifnode_to_req(); - return GetProfileString(table, name) + str.str(); +void AgentProfile::Log() { } -void AgentProfile::Log() { - time_t now; - time(&now); - - DBPartition *partition = agent_->db()->GetPartition(0); - TaskScheduler *sched = agent_->task_scheduler(); - cout << "Time : " << setw(4) << (now - start_time_) - << " #DBQueueLen(Curr/Total/Max) <" - << " " << partition->request_queue_len() - << " " << partition->total_request_count() - << " " << partition->max_request_queue_len() << ">" - << " #Task(Req/Done/Cancel) <" << sched->enqueue_count() - << " " << sched->done_count() - << " " << sched->cancel_count() << ">" - << endl; - - AgentConfig *cfg = agent_->cfg(); - cout << " " << GetInterfaceProfileString(agent_->interface_table(), - "Interface") << endl; - cout << " " << GetProfileString(agent_->vn_table(), "VN") << endl; - cout << " " << GetProfileString(agent_->physical_device_vn_table(), - "Dev-Vn") << endl; - cout << " " << GetProfileString(cfg->cfg_vm_interface_table(), - "Cfg-VMI") << endl; - cout << " " << GetProfileString(cfg->cfg_logical_port_table(), - "Cfg-LI") << endl; - cout << endl; +ProfileData *AgentProfile::GetLastProfileData() { + uint16_t index = seconds_history_index_ % kSecondsHistoryCount; + seconds_history_index_++; + return &seconds_history_data_[index]; +} + +ProfileData *AgentProfile::GetProfileData(uint16_t index) { + return &seconds_history_data_[index]; +} +////////////////////////////////////////////////////////////////////////////// +// ProfileData collection routines +////////////////////////////////////////////////////////////////////////////// +void ProfileData::DBTableStats::Reset() { + db_entry_count_ = 0; + walker_count_ = 0; + enqueue_count_ = 0; + input_count_ = 0; + notify_count_ = 0; +} + +void ProfileData::DBTableStats::Get(const DBTable *table) { + db_entry_count_ = table->Size(); + walker_count_ = table->walker_count(); + enqueue_count_ = table->enqueue_count(); + input_count_ = table->input_count(); + notify_count_ = table->notify_count(); +} + +void ProfileData::DBTableStats::Accumulate(const DBTableBase *table) { + db_entry_count_ += table->Size(); + walker_count_ += table->walker_count(); + enqueue_count_ += table->enqueue_count(); + input_count_ += table->input_count(); + notify_count_ += table->notify_count(); +} + +void ProfileData::Get(Agent *agent) { + std::ostringstream str; + str << boost::posix_time::second_clock::local_time(); + time_ = str.str(); + + DB::TableMap::const_iterator itr = + agent->db()->const_begin(); + DB::TableMap::const_iterator itrend = + agent->db()->const_end(); + + profile_stats_table_.clear(); + for ( ;itr != itrend; ++itr) { + if(itr->first.rfind(kV4UnicastRouteDbTableSuffix) != + std::string::npos) { + inet4_routes_.Accumulate(itr->second); + } else if (itr->first.rfind(kV6UnicastRouteDbTableSuffix) != + std::string::npos) { + inet6_routes_.Accumulate(itr->second); + } else if (itr->first.rfind(kL2RouteDbTableSuffix) != + std::string::npos) { + bridge_routes_.Accumulate(itr->second); + } else if (itr->first.rfind(kMcastRouteDbTableSuffix) != + std::string::npos) { + multicast_routes_.Accumulate(itr->second); + } else if (itr->first.rfind(kEvpnRouteDbTableSuffix) != + std::string::npos) { + evpn_routes_.Accumulate(itr->second); + } else { + ProfileData::DBTableStats stats; + stats.Get(dynamic_cast(itr->second)); + profile_stats_table_.insert(make_pair(itr->first,stats)); + } + } + + TaskScheduler *sched = TaskScheduler::GetInstance(); + task_stats_[0] = *sched->GetTaskGroupStats(sched->GetTaskId("Agent::FlowHandler")); + task_stats_[1] = *sched->GetTaskGroupStats(sched->GetTaskId("db::DBTable")); + task_stats_[2] = *sched->GetTaskGroupStats(sched->GetTaskId("Agent::StatsCollector")); + task_stats_[3] = *sched->GetTaskGroupStats(sched->GetTaskId("io::ReaderTask")); + task_stats_[4] = *sched->GetTaskGroupStats(sched->GetTaskId("Agent::PktFlowResponder")); + task_stats_[5] = *sched->GetTaskGroupStats(sched->GetTaskId("sandesh::RecvQueue")); + task_stats_[6] = *sched->GetTaskGroupStats(sched->GetTaskId("bgp::Config")); + task_stats_[7] = *sched->GetTaskGroupStats(sched->GetTaskId("Agent::KSync")); +} + +////////////////////////////////////////////////////////////////////////////// +// Sandesh ProfileData routines +////////////////////////////////////////////////////////////////////////////// +static void DBStatsToSandesh(SandeshDBTableStats *stats, const string &table, + const ProfileData::DBTableStats &db_stats) { + stats->set_table(table); + stats->set_db_entry_count(db_stats.db_entry_count_); + stats->set_input_count(db_stats.input_count_); + stats->set_walker_count(db_stats.walker_count_); + stats->set_enqueue_count(db_stats.enqueue_count_); + stats->set_notify_count(db_stats.notify_count_); +} + +static void GetDBTableStats(SandeshDBTableStatsInfo *stats, int index, + ProfileData *data) { + stats->set_index(index); + stats->set_time_str(data->time_); + std::vector db_stats_list; + + SandeshDBTableStats db_stats; + std::map::iterator itr = + data->profile_stats_table_.begin(); + + DBStatsToSandesh(&db_stats, "Ipv4 Unicast route", data->inet4_routes_); + db_stats_list.push_back(db_stats); + DBStatsToSandesh(&db_stats, "Ipv6 Unicast route", data->inet6_routes_); + db_stats_list.push_back(db_stats); + DBStatsToSandesh(&db_stats, "Multicast route", data->multicast_routes_); + db_stats_list.push_back(db_stats); + DBStatsToSandesh(&db_stats, "Evpn route", data->evpn_routes_); + db_stats_list.push_back(db_stats); + DBStatsToSandesh(&db_stats, "Bridge", data->bridge_routes_); + db_stats_list.push_back(db_stats); + while (itr != data->profile_stats_table_.end()) { + if(itr->first.find(kInterfaceDbTablePrefix) != std::string::npos) { + DBStatsToSandesh(&db_stats, "Interface", itr->second); + db_stats_list.push_back(db_stats); + } else if (itr->first.find(kMplsDbTablePrefix) != std::string::npos) { + DBStatsToSandesh(&db_stats, "Mpls", itr->second); + db_stats_list.push_back(db_stats); + } else if (itr->first.find(kLoadBalnceDbTablePrefix) != + std::string::npos) { + DBStatsToSandesh(&db_stats, "Loadbalancer", itr->second); + db_stats_list.push_back(db_stats); + } else if (itr->first.find(kVnDbTablePrefix) != std::string::npos) { + DBStatsToSandesh(&db_stats, "Vn", itr->second); + db_stats_list.push_back(db_stats); + } else if (itr->first.find(kVmDbTablePrefix) != std::string::npos) { + DBStatsToSandesh(&db_stats, "Vm", itr->second); + db_stats_list.push_back(db_stats); + } else if (itr->first.find(kVrfDbTablePrefix) != std::string::npos) { + DBStatsToSandesh(&db_stats, "Vrf", itr->second); + db_stats_list.push_back(db_stats); + } else if (itr->first.find(kAclDbTablePrefix) != std::string::npos) { + DBStatsToSandesh(&db_stats, "Acl", itr->second); + db_stats_list.push_back(db_stats); + } + ++itr; + } + + stats->set_stats(db_stats_list); +} + +void SandeshDBTableStatsRequest::HandleRequest() const { + SandeshDBTableStatsList *resp = new SandeshDBTableStatsList(); + resp->set_context(context()); + + Agent *agent = Agent::GetInstance(); + AgentProfile *profile = agent->oper_db()->agent_profile(); + uint16_t end = profile->seconds_history_index(); + uint16_t start = 0; + if (end > AgentProfile::kSecondsHistoryCount) + start = end - AgentProfile::kSecondsHistoryCount; + + std::vector stats_list; + for (uint16_t i = start; i < end; i++) { + uint16_t index = i % AgentProfile::kSecondsHistoryCount; + ProfileData *data = profile->GetProfileData(index); + SandeshDBTableStatsInfo stats; + GetDBTableStats(&stats, index, data); + stats_list.push_back(stats); + } + resp->set_stats(stats_list); + + resp->Response(); +} + +static void GetFlowStats(SandeshFlowStats *stats, int index, + ProfileData *data) { + stats->set_index(index); + stats->set_time_str(data->time_); + stats->set_add_count(data->flow_.add_count_); + stats->set_del_count(data->flow_.del_count_); + stats->set_reval_count(data->flow_.reval_count_); + stats->set_recompute_count(data->flow_.recompute_count_); +} + +void SandeshFlowStatsRequest::HandleRequest() const { + SandeshFlowStatsList *resp = new SandeshFlowStatsList(); + resp->set_context(context()); + + Agent *agent = Agent::GetInstance(); + AgentProfile *profile = agent->oper_db()->agent_profile(); + uint16_t end = profile->seconds_history_index(); + uint16_t start = 0; + if (end > AgentProfile::kSecondsHistoryCount) + start = end - AgentProfile::kSecondsHistoryCount; + + std::vector stats_list; + for (uint16_t i = start; i < end; i++) { + uint16_t index = i % AgentProfile::kSecondsHistoryCount; + ProfileData *data = profile->GetProfileData(index); + SandeshFlowStats stats; + GetFlowStats(&stats, index, data); + stats_list.push_back(stats); + } + resp->set_stats(stats_list); + resp->Response(); +} + +static void GetTaskStats(TaskProfileStats *stats, int index, + ProfileData *data) { + stats->set_index(index); + + TaskStats *task_stats = NULL; + // Flow Handler + task_stats = &data->task_stats_[0]; + stats->set_flow_wait(task_stats->wait_count_); + stats->set_flow_run(task_stats->enqueue_count_); + stats->set_flow_defer(task_stats->defer_count_); + + // DB + task_stats = &data->task_stats_[1]; + stats->set_db_wait(task_stats->wait_count_); + stats->set_db_run(task_stats->enqueue_count_); + stats->set_db_defer(task_stats->defer_count_); + + // Stats Collector + task_stats = &data->task_stats_[2]; + stats->set_stats_wait(task_stats->wait_count_); + stats->set_stats_run(task_stats->enqueue_count_); + stats->set_stats_defer(task_stats->defer_count_); + + // Io-Reader + task_stats = &data->task_stats_[3]; + stats->set_io_wait(task_stats->wait_count_); + stats->set_io_run(task_stats->enqueue_count_); + stats->set_io_defer(task_stats->defer_count_); + + // Agent::PktFlowResponder + task_stats = &data->task_stats_[4]; + stats->set_flow_resp_wait(task_stats->wait_count_); + stats->set_flow_resp_run(task_stats->enqueue_count_); + stats->set_flow_resp_defer(task_stats->defer_count_); + + // Sadnesh::RecvQueue + task_stats = &data->task_stats_[5]; + stats->set_sandesh_rcv_wait(task_stats->wait_count_); + stats->set_sandesh_rcv_run(task_stats->enqueue_count_); + stats->set_sandesh_rcv_defer(task_stats->defer_count_); + + // bgp::Config + task_stats = &data->task_stats_[6]; + stats->set_bgp_cfg_wait(task_stats->wait_count_); + stats->set_bgp_cfg_run(task_stats->enqueue_count_); + stats->set_bgp_cfg_defer(task_stats->defer_count_); + + // KSync + task_stats = &data->task_stats_[7]; + stats->set_ksync_wait(task_stats->wait_count_); + stats->set_ksync_run(task_stats->enqueue_count_); + stats->set_ksync_defer(task_stats->defer_count_); +} + +void SandeshTaskStatsRequest::HandleRequest() const { + SandeshTaskStatsList *resp = new SandeshTaskStatsList(); + resp->set_context(context()); + + Agent *agent = Agent::GetInstance(); + AgentProfile *profile = agent->oper_db()->agent_profile(); + uint16_t end = profile->seconds_history_index(); + uint16_t start = 0; + if (end > AgentProfile::kSecondsHistoryCount) + start = end - AgentProfile::kSecondsHistoryCount; + + std::vector stats_list; + for (uint16_t i = start; i < end; i++) { + uint16_t index = i % AgentProfile::kSecondsHistoryCount; + ProfileData *data = profile->GetProfileData(index); + TaskProfileStats stats; + GetTaskStats(&stats, index, data); + stats_list.push_back(stats); + } + resp->set_stats(stats_list); + resp->Response(); } diff --git a/src/vnsw/agent/oper/agent_profile.h b/src/vnsw/agent/oper/agent_profile.h index f6f0e10099b..1235a958a04 100644 --- a/src/vnsw/agent/oper/agent_profile.h +++ b/src/vnsw/agent/oper/agent_profile.h @@ -3,12 +3,92 @@ */ #ifndef SRC_VNSW_AGENT_OPER_PROFILE_H_ #define SRC_VNSW_AGENT_OPER_PROFILE_H_ +#include "db/db.h" class Agent; class Timer; +class ProfileData { +public: + struct WorkQueueStats { + uint64_t queue_count_; + uint64_t enqueue_count_; + uint64_t dequeue_count_; + uint64_t max_queue_count_; + uint64_t task_start_count_; + void Get(); + }; + + struct DBTableStats { + uint64_t db_entry_count_; + uint64_t walker_count_; + uint64_t enqueue_count_; + uint64_t input_count_; + uint64_t notify_count_; + void Get(const DBTable *table); + void Accumulate(const DBTableBase *table); + void Reset(); + }; + + struct FlowStats { + uint64_t add_count_; + uint64_t del_count_; + uint64_t reval_count_; + uint64_t recompute_count_; + WorkQueueStats pkt_flow_queue_count_; + void Get(); + }; + + struct PktStats { + uint64_t arp_count_; + uint64_t dhcp_count_; + uint64_t dns_count_; + uint64_t icmp_count_; + void Get(); + }; + struct XmppStats { + uint64_t inet4_add_count_; + uint64_t inet4_del_count_; + uint64_t inet6_add_count_; + uint64_t inet6_del_count_; + uint64_t mcast_add_count_; + uint64_t mcast_del_count_; + uint64_t bridge_add_count_; + uint64_t bridge_del_count_; + void Get(); + }; + + struct NovaIpcStats { + uint64_t add_count_; + uint64_t del_count_; + void Get(); + }; + + void Get(Agent *agent); +public: + std::string time_; + FlowStats flow_; + PktStats pkt_; + DBTableStats inet4_routes_; + DBTableStats inet6_routes_; + DBTableStats bridge_routes_; + DBTableStats multicast_routes_; + DBTableStats evpn_routes_; + XmppStats rx_stats_; + XmppStats tx_stats_; + WorkQueueStats ksync_tx_queue_count_; + WorkQueueStats ksync_rx_queue_count_; + TaskStats task_stats_[8]; + std::map profile_stats_table_; +}; + class AgentProfile { public: - static const uint32_t kProfileTimeout = 2000; + static const uint32_t kProfileTimeout = 1000; + static const uint16_t kSecondsHistoryCount = 300; + static const uint16_t kMinutesHistoryCount = 60; + static const uint16_t kHoursHistoryCount = 24; + typedef boost::function PktFlowStatsCb; + AgentProfile(Agent *agent, bool enable); ~AgentProfile(); bool Init(); @@ -16,12 +96,38 @@ class AgentProfile { bool TimerRun(); void Log(); + + void RegisterPktFlowStatsCb(PktFlowStatsCb cb) { pkt_flow_stats_cb_ = cb; } + void AddProfileData(ProfileData *data); + ProfileData *GetProfileData(uint16_t index); + uint16_t seconds_history_index() const { return seconds_history_index_; } + private: + ProfileData *GetLastProfileData(); + Agent *agent_; Timer *timer_; time_t start_time_; bool enable_; + ProfileData one_min_data_; + ProfileData five_min_data_; + ProfileData fifteen_min_data_; + ProfileData thirty_min_data_; + ProfileData one_hr_data_; + ProfileData four_hr_data_; + ProfileData eight_hr_data_; + ProfileData sixteen_hr_data_; + ProfileData twentyfour_hr_data_; + + uint16_t seconds_history_index_; + ProfileData seconds_history_data_[kSecondsHistoryCount]; + uint16_t minutes_history_index_; + ProfileData minutes_history_data_[kMinutesHistoryCount]; + uint16_t hours_history_index_; + ProfileData hours_history_data_[kHoursHistoryCount]; + + PktFlowStatsCb pkt_flow_stats_cb_; DISALLOW_COPY_AND_ASSIGN(AgentProfile); }; diff --git a/src/vnsw/agent/oper/agent_profile.sandesh b/src/vnsw/agent/oper/agent_profile.sandesh new file mode 100644 index 00000000000..1d48b97fd80 --- /dev/null +++ b/src/vnsw/agent/oper/agent_profile.sandesh @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. + */ + +struct SandeshDBTableStats { + 1: string table; + 2: u64 db_entry_count; + 3: u64 walker_count; + 4: u64 enqueue_count; + 5: u64 input_count; + 6: u64 notify_count; +} + +struct SandeshDBTableStatsInfo { + 1: u16 index; + 2: string time_str; + 3: list stats; +} + +response sandesh SandeshDBTableStatsList { + 1: list stats; +} + +request sandesh SandeshDBTableStatsRequest { + 1: u16 count; // send data for last 'count' entries +} + +struct SandeshFlowStats { + 1: u16 index; + 2: string time_str; + 3: u64 add_count; + 4: u64 del_count; + 5: u64 reval_count; + 6: u64 recompute_count; +} + +response sandesh SandeshFlowStatsList { + 1: list stats; +} + +request sandesh SandeshFlowStatsRequest { + 1: u16 count; // send data for last 'count' entries +} + +struct TaskProfileStats { + 1: u16 index; + 2: i32 flow_run; + 3: i32 flow_wait; + 4: i32 flow_defer; + 5: i32 db_run; + 6: i32 db_wait; + 7: i32 db_defer; + 8: i32 stats_run; + 9: i32 stats_wait; + 10: i32 stats_defer; + 11: i32 io_run; + 12: i32 io_wait; + 13: i32 io_defer; + 14: i32 flow_resp_run; + 15: i32 flow_resp_wait; + 16: i32 flow_resp_defer; + 17: i32 sandesh_rcv_run; + 18: i32 sandesh_rcv_wait; + 19: i32 sandesh_rcv_defer; + 20: i32 bgp_cfg_run; + 21: i32 bgp_cfg_wait; + 22: i32 bgp_cfg_defer; + 23: i32 ksync_run; + 24: i32 ksync_wait; + 25: i32 ksync_defer; +} + +response sandesh SandeshTaskStatsList { + 1: list stats; +} + +request sandesh SandeshTaskStatsRequest { + 1: u16 count; // send data for last 'count' entries +} + diff --git a/src/vnsw/agent/oper/operdb_init.cc b/src/vnsw/agent/oper/operdb_init.cc index 53b8e5f94bb..8cd9fc4ab06 100644 --- a/src/vnsw/agent/oper/operdb_init.cc +++ b/src/vnsw/agent/oper/operdb_init.cc @@ -182,7 +182,7 @@ void OperDB::CreateDBTables(DB *db) { DBTableCreate(db, agent_, this, "db.physical_device_vn.0"); agent_->set_physical_device_vn_table(dev_vn_table); - profile_.reset(new AgentProfile(agent_, false)); + profile_.reset(new AgentProfile(agent_, true)); } void OperDB::Init() { diff --git a/src/vnsw/agent/oper/operdb_init.h b/src/vnsw/agent/oper/operdb_init.h index 90a454a5d38..657cf404484 100644 --- a/src/vnsw/agent/oper/operdb_init.h +++ b/src/vnsw/agent/oper/operdb_init.h @@ -36,6 +36,7 @@ class OperDB { Agent *agent() const { return agent_; } MulticastHandler *multicast() const { return multicast_.get(); } GlobalVrouter *global_vrouter() const { return global_vrouter_.get(); } + AgentProfile *agent_profile() const { return profile_.get(); } PathPreferenceModule *route_preference_module() const { return route_preference_module_.get(); } diff --git a/src/vnsw/agent/pkt/flow_table.cc b/src/vnsw/agent/pkt/flow_table.cc index a45675c5f0c..db50ab9862b 100644 --- a/src/vnsw/agent/pkt/flow_table.cc +++ b/src/vnsw/agent/pkt/flow_table.cc @@ -32,6 +32,7 @@ #include "oper/vrf.h" #include "oper/vm.h" #include "oper/sg.h" +#include "oper/agent_profile.h" #include "filter/packet_header.h" #include "filter/acl.h" @@ -48,6 +49,8 @@ #include "uve/vn_uve_table.h" #include "uve/vrouter_uve_entry.h" +static void UpdateStats(FlowTable::StatsType type, FlowProfStats *stats); + using boost::assign::map_list_of; const std::map FlowEntry::FlowPolicyStateStr = map_list_of @@ -1664,6 +1667,7 @@ FlowEntry *FlowTable::Allocate(const FlowKey &key) { flow->set_deleted(false); DeleteFlowInfo(flow); } else { + UpdateStats(ADD, &stats_); flow->stats_.setup_time = UTCTimestampUsec(); agent_->stats()->incr_flow_created(); agent_->stats()->UpdateFlowAddMinMaxStats(flow->stats_.setup_time); @@ -1821,6 +1825,7 @@ void FlowTable::DeleteAclFlows(const AclDBEntry *acl) while(fe_tree_it != fe_tree.end()) { const FlowKey &fekey = (*fe_tree_it)->key(); ++fe_tree_it; + UpdateStats(DEL, &stats_); Delete(fekey, true); } } @@ -2578,10 +2583,12 @@ void FlowTable::ResyncVnFlows(const VnEntry *vn) { fe->is_flags_set(FlowEntry::UnknownUnicastFlood)) { fe->MakeShortFlow(FlowEntry::SHORT_NO_DST_ROUTE); fe->GetPolicyInfo(vn); + UpdateStats(REVAL, &stats_); ResyncAFlow(fe, true); continue; } fe->GetPolicyInfo(vn); + UpdateStats(REVAL, &stats_); ResyncAFlow(fe, true); AddFlowInfo(fe); FlowInfo flow_info; @@ -2606,6 +2613,7 @@ void FlowTable::ResyncAclFlows(const AclDBEntry *acl) FlowEntry *fe = (*fet_it).get(); DeleteFlowInfo(fe); fe->GetPolicyInfo(); + UpdateStats(REVAL, &stats_); ResyncAFlow(fe, true); AddFlowInfo(fe); FlowInfo flow_info; @@ -2631,6 +2639,7 @@ void FlowTable::ResyncEcmpInfo(const RouteFlowKey &key, const AgentRoute *rt) { continue; } + UpdateStats(REVAL, &stats_); UpdateEcmpInfo(flow); FlowEntry *rflow = flow->reverse_flow_entry(); if (rflow) { @@ -2657,6 +2666,7 @@ void FlowTable::ResyncRpfNH(const RouteFlowKey &key, const AgentRoute *rt) { } if (flow->SetRpfNH(this, rt) == true) { + UpdateStats(REVAL, &stats_); flow->UpdateKSync(this, true); FlowInfo flow_info; flow->FillFlowInfo(flow_info); @@ -2716,6 +2726,7 @@ void FlowTable::FlowRecompute(RouteFlowInfo *rt_info, continue; } if (fe->set_pending_recompute(true)) { + UpdateStats(RECOMPUTE, &stats_); agent_->pkt()->pkt_handler()->SendMessage(PktHandler::FLOW, new FlowTaskMsg(fe)); } @@ -2742,6 +2753,7 @@ void FlowTable::FlowL2Recompute(RouteFlowInfo *rt_info) { fe = fe->reverse_flow_entry(); } if (fe->set_pending_recompute(true)) { + UpdateStats(RECOMPUTE, &stats_); agent_->pkt()->pkt_handler()->SendMessage(PktHandler::FLOW, new FlowTaskMsg(fe)); } @@ -2768,8 +2780,10 @@ void FlowTable::IterateFlowInfoEntries(const RouteFlowKey &key, FlowEntryCb cb) FLOW_TRACE(Trace, "Evaluate Route Flows", flow_info); DeleteFlowInfo(fe); if (cb(fe) == false) { + UpdateStats(DEL, &stats_); fet.erase(fet_it); } else { + UpdateStats(REVAL, &stats_); ResyncAFlow(fe, true); AddFlowInfo(fe); } @@ -2805,6 +2819,7 @@ void FlowTable::ResyncVmPortFlows(const VmInterface *intf) { } DeleteFlowInfo(fe); fe->GetPolicyInfo(intf->vn()); + UpdateStats(REVAL, &stats_); ResyncAFlow(fe, true); AddFlowInfo(fe); FlowInfo flow_info; @@ -3588,6 +3603,7 @@ void FlowTable::DeleteVnFlows(const VnEntry *vn) FlowEntryTree fet = vn_it->second->fet; FlowEntryTree::iterator fet_it; for (fet_it = fet.begin(); fet_it != fet.end(); ++fet_it) { + UpdateStats(DEL, &stats_); Delete((*fet_it)->key(), true); } } @@ -3618,6 +3634,7 @@ void FlowTable::DeleteVmIntfFlows(const Interface *intf) FlowEntryTree fet = intf_it->second->fet; FlowEntryTree::iterator fet_it; for (fet_it = fet.begin(); fet_it != fet.end(); ++fet_it) { + UpdateStats(DEL, &stats_); Delete((*fet_it)->key(), true); } } @@ -3928,10 +3945,15 @@ FlowTable::FlowTable(Agent *agent) : delete_queue_(new WorkQueue( TaskScheduler::GetInstance()->GetTaskId("Agent::FlowHandler"), PktHandler::FLOW, - boost::bind(&FlowTable::FlowDelete, this, _1))) { + boost::bind(&FlowTable::FlowDelete, this, _1))), + stats_() { max_vm_flows_ = (uint32_t) (agent->ksync()->flowtable_ksync_obj()->flow_table_entries_count() * agent->params()->max_vm_flows()) / 100; + + AgentProfile *profile = agent_->oper_db()->agent_profile(); + profile->RegisterPktFlowStatsCb(boost::bind(&FlowTable::SetProfileData, + this, _1)); } FlowTable::~FlowTable() { @@ -3969,3 +3991,31 @@ void FlowTable::FreeReq(FlowEntryPtr &flow) { flow.reset(); delete_queue_->Enqueue(req); } + +////////////////////////////////////////////////////////////////////////////// +// Set profile information +////////////////////////////////////////////////////////////////////////////// +void UpdateStats(FlowTable::StatsType type, FlowProfStats *stats) { + switch (type) { + case FlowTable::ADD: + stats->add_count_++; + break; + case FlowTable::DEL: + stats->delete_count_++; + break; + case FlowTable::REVAL: + stats->revaluate_count_++; + break; + case FlowTable::RECOMPUTE: + stats->recompute_count_++; + break; + default: + break; + } +} + +void FlowTable::SetProfileData(ProfileData *data) { + data->flow_.add_count_ = stats_.add_count_; + data->flow_.del_count_ = stats_.delete_count_; + data->flow_.reval_count_ = stats_.revaluate_count_; +} diff --git a/src/vnsw/agent/pkt/flow_table.h b/src/vnsw/agent/pkt/flow_table.h index ec42139f6c0..f8f8b484739 100644 --- a/src/vnsw/agent/pkt/flow_table.h +++ b/src/vnsw/agent/pkt/flow_table.h @@ -57,9 +57,21 @@ class FlowTableKSyncEntry; class NhListener; class NhState; class FlowDeleteReq; +class ProfileData; typedef boost::intrusive_ptr FlowEntryPtr; typedef boost::intrusive_ptr NhStatePtr; +struct FlowProfStats { + uint64_t add_count_; + uint64_t delete_count_; + uint64_t revaluate_count_; + uint64_t recompute_count_; + + FlowProfStats() : + add_count_(0), delete_count_(0), revaluate_count_(0), recompute_count_(0) { + } +}; + struct RevFlowDepParams { uuid rev_uuid_; IpAddress sip_; @@ -678,6 +690,13 @@ class FlowTable { typedef Patricia::Tree RouteFlowTree; typedef boost::function FlowEntryCb; + enum StatsType { + ADD, + DEL, + REVAL, + RECOMPUTE + }; + struct VnFlowHandlerState : public DBState { AclDBEntryConstRef acl_; AclDBEntryConstRef macl_; @@ -814,6 +833,9 @@ class FlowTable { friend class PktFlowInfo; friend class FlowTableKSyncEntry; friend void intrusive_ptr_release(FlowEntry *fe); + + const FlowProfStats *flow_stats() const { return &stats_; } + void SetProfileData(ProfileData *data); private: static SecurityGroupList default_sg_list_; @@ -845,6 +867,8 @@ class FlowTable { // maintain the linklocal flow info against allocated fd, debug purpose only LinkLocalFlowInfoMap linklocal_flow_info_map_; + FlowProfStats stats_; + void AclNotify(DBTablePartBase *part, DBEntryBase *e); void IntfNotify(DBTablePartBase *part, DBEntryBase *e); void VnNotify(DBTablePartBase *part, DBEntryBase *e);