LCOV - code coverage report
Current view: top level - vnsw/agent/vrouter/flow_stats - session_stats_collector.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 578 1287 44.9 %
Date: 2026-11-09 02:10:49 Functions: 54 101 53.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include <bitset>
       7             : #include <pkt/flow_table.h>
       8             : #include <pkt/flow_mgmt/flow_mgmt_request.h>
       9             : #include <uve/stats_collector.h>
      10             : #include <uve/interface_uve_stats_table.h>
      11             : #include <sandesh/common/flow_types.h>
      12             : #include <init/agent_param.h>
      13             : #include <vrouter/flow_stats/session_stats_collector.h>
      14             : #include <vrouter/ksync/ksync_init.h>
      15             : #include <oper/tag.h>
      16             : #include <oper/security_logging_object.h>
      17             : #include <oper/global_vrouter.h>
      18             : #include <vrouter/flow_stats/flow_stats_collector.h>
      19             : #include <vrouter/flow_stats/flow_stats_types.h>
      20             : #include <cmn/agent_factory.h>
      21             : 
      22             : // setting work queue max size as 4M
      23             : #define DEFAULT_SSC_REQUEST_QUEUE_SIZE 4*1024*1024
      24             : #define MAX_SSC_REQUEST_QUEUE_ITERATIONS 256
      25             : 
      26             : SandeshTraceBufferPtr SessionStatsTraceBuf(SandeshTraceBufferCreate(
      27             :     "SessionStats", 4000));
      28             : 
      29             : bool session_debug_ = false;
      30           2 : SessionStatsCollector::SessionStatsCollector(boost::asio::io_context &io,
      31             :                                        AgentUveBase *uve,
      32             :                                        uint32_t instance_id,
      33             :                                        FlowStatsManager *aging_module,
      34           2 :                                        SessionStatsCollectorObject *obj) :
      35             :         StatsCollector(TaskScheduler::GetInstance()->GetTaskId
      36             :                        (kTaskSessionStatsCollector), instance_id,
      37             :                        io, kSessionStatsTimerInterval, "Session stats collector"),
      38           2 :         agent_uve_(uve),
      39           2 :         task_id_(uve->agent()->task_scheduler()->GetTaskId
      40           2 :                  (kTaskSessionStatsCollector)),
      41           2 :         session_ep_iteration_key_(), session_agg_iteration_key_(),
      42           2 :         session_iteration_key_(),
      43           2 :         request_queue_(agent_uve_->agent()->task_scheduler()->
      44             :                        GetTaskId(kTaskSessionStatsCollectorEvent),
      45             :                        instance_id,
      46             :                        boost::bind(&SessionStatsCollector::RequestHandler,
      47             :                                    this, _1),
      48             :                        DEFAULT_SSC_REQUEST_QUEUE_SIZE,
      49             :                        MAX_SSC_REQUEST_QUEUE_ITERATIONS ),
      50           4 :         session_msg_list_(agent_uve_->agent()->params()->max_endpoints_per_session_msg(),
      51           4 :                           SessionEndpoint()),
      52           2 :         session_msg_index_(0), instance_id_(instance_id),
      53           2 :         flow_stats_manager_(aging_module), parent_(obj), session_task_(NULL),
      54           6 :         current_time_(GetCurrentTime()), session_task_starts_(0) {
      55           2 :         request_queue_.set_name("Session stats collector event queue");
      56             :         request_queue_.set_measure_busy_time
      57           2 :             (agent_uve_->agent()->MeasureQueueDelay());
      58             :         request_queue_.SetEntryCallback
      59           2 :             (boost::bind(&SessionStatsCollector::RequestHandlerEntry, this));
      60             :         request_queue_.SetExitCallback
      61           2 :             (boost::bind(&SessionStatsCollector::RequestHandlerExit, this, _1));
      62           2 :         request_queue_.SetBounded(true);
      63           2 :         InitDone();
      64           2 : }
      65             : 
      66           4 : SessionStatsCollector::~SessionStatsCollector() {
      67           2 :     flow_stats_manager_->FreeIndex(instance_id_);
      68           4 : }
      69             : 
      70         555 : uint64_t SessionStatsCollector::GetCurrentTime() {
      71         555 :     return UTCTimestampUsec();
      72             : }
      73             : 
      74           2 : void SessionStatsCollector::Shutdown() {
      75           2 :     StatsCollector::Shutdown();
      76           2 :     request_queue_.Shutdown();
      77           2 : }
      78             : 
      79           2 : void SessionStatsCollector::RegisterDBClients() {
      80           2 :     if (agent_uve_->agent()->slo_table()) {
      81           2 :         slo_listener_id_ = agent_uve_->agent()->slo_table()->Register(
      82             :                             boost::bind(&SessionStatsCollector::SloNotify, this,
      83             :                                         _1, _2));
      84             :     }
      85           2 : }
      86             : 
      87           6 : bool SessionStatsCollector::Run() {
      88           6 :     if (session_endpoint_map_.size() == 0) {
      89           0 :         return true;
      90             :      }
      91             : 
      92             :     // Start task to scan the entries
      93           6 :     if (session_task_ == NULL) {
      94           6 :         session_task_starts_++;
      95             : 
      96           6 :         if (session_debug_) {
      97           0 :             LOG(DEBUG,
      98             :                 UTCUsecToString(ClockMonotonicUsec())
      99             :                 << " SessionTasks Num " << session_task_starts_
     100             :                 << " session_ep visited " << session_ep_visited_
     101             :                 << " Request count " << request_queue_.Length());
     102             :         }
     103           6 :         session_ep_visited_ = 0;
     104           6 :         session_task_ = new SessionTask(this);
     105           6 :         agent_uve_->agent()->task_scheduler()->Enqueue(session_task_);
     106             :     }
     107           6 :     return true;
     108             : }
     109             : 
     110             : 
     111           3 : bool FlowStatsManager::UpdateSessionThreshold() {
     112           3 :     uint64_t curr_time = FlowStatsCollector::GetCurrentTime();
     113           3 :     bool export_rate_calculated = false;
     114           3 :     uint32_t exp_rate_without_sampling = 0;
     115             : 
     116             :     /* If flows are not being exported, no need to update threshold */
     117           3 :     if (!session_export_count_) {
     118           3 :         return true;
     119             :     }
     120             : 
     121             :     // Calculate Flow Export rate
     122           0 :     if (prev_flow_export_rate_compute_time_) {
     123           0 :         uint64_t diff_secs = 0;
     124           0 :         uint64_t diff_micro_secs = curr_time -
     125           0 :             prev_flow_export_rate_compute_time_;
     126           0 :         if (diff_micro_secs) {
     127           0 :             diff_secs = diff_micro_secs/1000000;
     128             :         }
     129           0 :         if (diff_secs) {
     130           0 :             uint32_t session_export_count = session_export_count_reset();
     131           0 :             session_export_rate_ = session_export_count/diff_secs;
     132           0 :             exp_rate_without_sampling =
     133           0 :                 session_export_without_sampling_reset()/diff_secs;
     134           0 :             prev_flow_export_rate_compute_time_ = curr_time;
     135           0 :             export_rate_calculated = true;
     136             :         }
     137             :     } else {
     138           0 :         prev_flow_export_rate_compute_time_ = curr_time;
     139           0 :         session_export_count_ = 0;
     140           0 :         return true;
     141             :     }
     142             : 
     143           0 :     uint32_t cfg_rate = agent_->oper_db()->global_vrouter()->
     144           0 :                             flow_export_rate();
     145             :     /* No need to update threshold when flow_export_rate is NOT calculated
     146             :      * and configured flow export rate has not changed */
     147           0 :     if (!export_rate_calculated &&
     148           0 :         (cfg_rate == prev_cfg_flow_export_rate_)) {
     149           0 :         return true;
     150             :     }
     151           0 :     uint64_t cur_t = threshold(), new_t = 0;
     152             :     // Update sampling threshold based on flow_export_rate_
     153           0 :     if (session_export_rate_ < ((double)cfg_rate) * 0.8) {
     154             :         /* There are two reasons why we can be here.
     155             :          * 1. None of the flows were sampled because we never crossed
     156             :          *    80% of configured flow-export-rate.
     157             :          * 2. In scale setups, the threshold was updated to high value because
     158             :          *    of which flow-export-rate has dropped drastically.
     159             :          * Threshold should be updated here depending on which of the above two
     160             :          * situations we are in. */
     161           0 :         if (!sessions_sampled_atleast_once_) {
     162           0 :             UpdateThreshold(kDefaultFlowSamplingThreshold, false);
     163             :         } else {
     164           0 :             if (session_export_rate_ < ((double)cfg_rate) * 0.5) {
     165           0 :                 UpdateThreshold((threshold_ / 4), false);
     166             :             } else {
     167           0 :                 UpdateThreshold((threshold_ / 2), false);
     168             :             }
     169             :         }
     170           0 :     } else if (session_export_rate_ > (cfg_rate * 3)) {
     171           0 :         UpdateThreshold((threshold_ * 4), true);
     172           0 :     } else if (session_export_rate_ > (cfg_rate * 2)) {
     173           0 :         UpdateThreshold((threshold_ * 3), true);
     174           0 :     } else if (session_export_rate_ > ((double)cfg_rate) * 1.25) {
     175           0 :         UpdateThreshold((threshold_ * 2), true);
     176             :     }
     177           0 :     prev_cfg_flow_export_rate_ = cfg_rate;
     178           0 :     new_t = threshold();
     179           0 :     FLOW_EXPORT_STATS_TRACE(session_export_rate_, exp_rate_without_sampling,
     180             :                             cur_t, new_t);
     181           0 :     return true;
     182             : }
     183             : 
     184             : /////////////////////////////////////////////////////////////////////////////
     185             : // Utility methods to enqueue events into work-queue
     186             : /////////////////////////////////////////////////////////////////////////////
     187         230 : void SessionStatsCollector::AddEvent(const FlowEntryPtr &flow) {
     188             :     boost::shared_ptr<SessionStatsReq>
     189             :         req(new SessionStatsReq(SessionStatsReq::ADD_SESSION, flow,
     190         230 :                                 GetCurrentTime()));
     191         230 :     request_queue_.Enqueue(req);
     192         230 : }
     193             : 
     194         144 : void SessionStatsCollector::DeleteEvent(const FlowEntryPtr &flow,
     195             :                                         const RevFlowDepParams &params) {
     196             :     boost::shared_ptr<SessionStatsReq>
     197             :         req(new SessionStatsReq(SessionStatsReq::DELETE_SESSION, flow,
     198         144 :                                 GetCurrentTime(), params));
     199         144 :     request_queue_.Enqueue(req);
     200         144 : }
     201             : 
     202           0 : void SessionStatsCollector::UpdateSessionStatsEvent(const FlowEntryPtr &flow,
     203             :                                           uint32_t bytes,
     204             :                                           uint32_t packets,
     205             :                                           uint32_t oflow_bytes,
     206             :                                           const boost::uuids::uuid &u) {
     207             :     boost::shared_ptr<SessionStatsReq>
     208             :         req(new SessionStatsReq(SessionStatsReq::UPDATE_SESSION_STATS, flow,
     209           0 :                                 bytes, packets, oflow_bytes, u));
     210           0 :     request_queue_.Enqueue(req);
     211           0 : }
     212             : 
     213           0 : void SessionStatsCollector::DispatchSessionMsg(const std::vector<SessionEndpoint> &lst) {
     214           0 :     flow_stats_manager_->UpdateSessionMsgExportStats(1);
     215           0 :     flow_stats_manager_->UpdateSessionSampleExportStats(lst.size());
     216           0 :     SESSION_ENDPOINT_OBJECT_LOG("", SandeshLevel::SYS_INFO, lst);
     217           0 : }
     218             : 
     219           0 : void SessionStatsCollector::EnqueueSessionMsg() {
     220           0 :     session_msg_index_++;
     221           0 :     if (session_msg_index_ ==
     222           0 :         agent_uve_->agent()->params()->max_endpoints_per_session_msg()) {
     223           0 :         DispatchSessionMsg(session_msg_list_);
     224           0 :         session_msg_index_ = 0;
     225             :     }
     226           0 : }
     227             : 
     228           6 : void SessionStatsCollector::DispatchPendingSessionMsg() {
     229           6 :     if (session_msg_index_ == 0) {
     230           6 :         return;
     231             :     }
     232             : 
     233           0 :     vector<SessionEndpoint>::const_iterator first = session_msg_list_.begin();
     234           0 :     vector<SessionEndpoint>::const_iterator last = session_msg_list_.begin() +
     235           0 :                                                     session_msg_index_;
     236           0 :     vector<SessionEndpoint> new_list(first, last);
     237           0 :     DispatchSessionMsg(new_list);
     238           0 :     session_msg_index_ = 0;
     239           0 : }
     240             : 
     241          26 : uint8_t SessionStatsCollector::GetSessionMsgIdx() {
     242          26 :     SessionEndpoint &obj = session_msg_list_[session_msg_index_];
     243          26 :     obj = SessionEndpoint();
     244          26 :     return session_msg_index_;
     245             : }
     246             : 
     247         155 : bool SessionStatsCollector::RequestHandlerEntry() {
     248         155 :     current_time_ = GetCurrentTime();
     249         155 :     return true;
     250             : }
     251             : 
     252         155 : void SessionStatsCollector::RequestHandlerExit(bool done) {
     253         155 : }
     254             : 
     255         374 : bool SessionStatsCollector::RequestHandler(boost::shared_ptr<SessionStatsReq> req) {
     256         374 :     FlowEntry *flow = req->flow();
     257         374 :     FlowEntry *rflow = req->reverse_flow();
     258         518 :     FLOW_LOCK(flow, rflow, FlowEvent::FLOW_MESSAGE);
     259             : 
     260         374 :     switch (req->event()) {
     261         230 :     case SessionStatsReq::ADD_SESSION: {
     262         230 :         AddSession(flow, req->time());
     263         230 :         break;
     264             :     }
     265             : 
     266         144 :     case SessionStatsReq::DELETE_SESSION: {
     267         144 :         DeleteSession(flow, flow->uuid(), req->time(), &req->params());
     268         144 :         break;
     269             :     }
     270             : 
     271           0 :     case SessionStatsReq::UPDATE_SESSION_STATS: {
     272           0 :         EvictedSessionStatsUpdate(req->flow(), req->bytes(), req->packets(),
     273           0 :                                   req->oflow_bytes(), req->uuid());
     274           0 :         break;
     275             :     }
     276             : 
     277           0 :     default:
     278           0 :          assert(0);
     279             :     }
     280             : 
     281         374 :     return true;
     282         374 : }
     283             : 
     284        1278 : bool SessionEndpointKey::IsLess(const SessionEndpointKey &rhs) const {
     285        1278 :     if (vmi_cfg_name != rhs.vmi_cfg_name) {
     286         289 :         return vmi_cfg_name < rhs.vmi_cfg_name;
     287             :     }
     288         989 :     if (local_vn != rhs.local_vn) {
     289          28 :         return local_vn < rhs.local_vn;
     290             :     }
     291         961 :     if (remote_vn != rhs.remote_vn) {
     292         145 :         return remote_vn < rhs.remote_vn;
     293             :     }
     294         816 :     if (local_tagset != rhs.local_tagset) {
     295           0 :         return local_tagset < rhs.local_tagset;
     296             :     }
     297         816 :     if (remote_tagset != rhs.remote_tagset) {
     298           0 :         return remote_tagset < rhs.remote_tagset;
     299             :     }
     300         816 :     if (remote_prefix != rhs.remote_prefix) {
     301           7 :         return remote_prefix < rhs.remote_prefix;
     302             :     }
     303         809 :     if (match_policy != rhs.match_policy) {
     304         109 :         return match_policy < rhs.match_policy;
     305             :     }
     306         700 :     if (is_client_session != rhs.is_client_session) {
     307         116 :         return is_client_session < rhs.is_client_session;
     308             :     }
     309         584 :     return is_si < rhs.is_si;
     310             : }
     311             : 
     312         116 : bool SessionEndpointKey::IsEqual(const SessionEndpointKey &rhs) const {
     313         116 :     if (vmi_cfg_name != rhs.vmi_cfg_name) {
     314           0 :         return false;
     315             :     }
     316         116 :     if (local_vn != rhs.local_vn) {
     317           2 :         return false;
     318             :     }
     319         114 :     if (remote_vn != rhs.remote_vn) {
     320           5 :         return false;
     321             :     }
     322         109 :     if (local_tagset != rhs.local_tagset) {
     323           0 :         return false;
     324             :     }
     325         109 :     if (remote_tagset != rhs.remote_tagset) {
     326           0 :         return false;
     327             :     }
     328         109 :     if (remote_prefix != rhs.remote_prefix) {
     329           0 :         return false;
     330             :     }
     331         109 :     if (match_policy != rhs.match_policy) {
     332          14 :         return false;
     333             :     }
     334          95 :     if (is_client_session != rhs.is_client_session) {
     335           0 :         return false;
     336             :     }
     337          95 :     if (is_si != rhs.is_si) {
     338           0 :         return false;
     339             :     }
     340          95 :     return true;
     341             : }
     342             : 
     343         406 : void SessionEndpointKey::Reset() {
     344         406 :     vmi_cfg_name = "";
     345         406 :     local_vn = "";
     346         406 :     remote_vn = "";
     347         406 :     local_tagset.clear();
     348         406 :     remote_tagset.clear();
     349         406 :     remote_prefix = "";
     350         406 :     match_policy = "";
     351         406 :     is_client_session = false;
     352         406 :     is_si = false;
     353         406 : }
     354             : 
     355        1198 : bool SessionAggKey::IsLess(const SessionAggKey &rhs) const {
     356        1198 :     if (local_ip != rhs.local_ip) {
     357          97 :         return local_ip < rhs.local_ip;
     358             :     }
     359        1101 :     if (server_port != rhs.server_port) {
     360         610 :         return server_port < rhs.server_port;
     361             :     }
     362         491 :     return proto < rhs.proto;
     363             : }
     364             : 
     365         116 : bool SessionAggKey::IsEqual(const SessionAggKey &rhs) const {
     366         116 :     if (local_ip != rhs.local_ip) {
     367           0 :         return false;
     368             :     }
     369         116 :     if (server_port != rhs.server_port) {
     370           0 :         return false;
     371             :     }
     372         116 :     if (proto != rhs.proto) {
     373           0 :         return false;
     374             :     }
     375         116 :     return true;
     376             : }
     377             : 
     378         423 : void SessionAggKey::Reset() {
     379         423 :     local_ip = IpAddress();
     380         423 :     server_port = 0;
     381         423 :     proto = 0;
     382         423 : }
     383             : 
     384         565 : bool SessionKey::IsLess(const SessionKey &rhs) const {
     385         565 :     if (remote_ip != rhs.remote_ip) {
     386          59 :         return remote_ip < rhs.remote_ip;
     387             :     }
     388         506 :     if (client_port != rhs.client_port) {
     389           0 :         return client_port < rhs.client_port;
     390             :     }
     391         506 :     return uuid < rhs.uuid;
     392             : }
     393             : 
     394         119 : bool SessionKey::IsEqual(const SessionKey &rhs) const {
     395         119 :     if (remote_ip != rhs.remote_ip) {
     396           0 :         return false;
     397             :     }
     398         119 :     if (client_port != rhs.client_port) {
     399           0 :         return false;
     400             :     }
     401         119 :     if (uuid != rhs.uuid) {
     402           3 :         return false;
     403             :     }
     404         116 :     return true;
     405             : }
     406             : 
     407         478 : void SessionKey::Reset() {
     408         478 :     remote_ip = IpAddress();
     409         478 :     client_port = 0;
     410         478 :     uuid = boost::uuids::nil_uuid();
     411         478 : }
     412             : 
     413         230 : bool SessionStatsCollector::GetSessionKey(FlowEntry* fe,
     414             :                                         SessionAggKey &session_agg_key,
     415             :                                         SessionKey    &session_key,
     416             :                                         SessionEndpointKey &session_endpoint_key) {
     417             :     /*
     418             :      * For non local flows always get the key for forward flow entry
     419             :      * If vms are in same compute node (local route)
     420             :      * Vrouter A  (Client)                <==>     Vrouter B (Server)
     421             :      * A->B (Ingress + Forwarding + Local)
     422             :      * B->A (Ingress + Reverse + Local)
     423             :      *
     424             :      * If vms are in different compute nodes
     425             :      * Vrouter A (Client)               <==>     Vrouter B (Server)
     426             :      * A->B (Ingress + Forwarding)             A->B (Egresss + Forward)
     427             :      * B->A (Egress + Reverse)                 B->A (Ingress + Reverse)
     428             :      */
     429             : 
     430             :     /*
     431             :      *  If it is non local reverse flow then NOP, actual
     432             :      *  config will be handled in fwd flow
     433             :      */
     434         410 :     if ((!(fe->is_flags_set(FlowEntry::LocalFlow))) &&
     435         410 :         (fe->is_flags_set(FlowEntry::ReverseFlow))) {
     436           0 :         return false;
     437             :     }
     438             : 
     439         230 :     const Interface *itf = fe->intf_entry();
     440         230 :     if (!itf) {
     441           2 :         return false;
     442             :     }
     443             : 
     444         228 :     if (itf->type() != Interface::VM_INTERFACE) {
     445           2 :         return false;
     446             :     }
     447             : 
     448         226 :     const VmInterface *vmi = static_cast<const VmInterface *>(itf);
     449         226 :     if (vmi->cfg_name().empty()) {
     450           0 :         return false;
     451             :     }
     452         226 :     const string &src_vn = !fe->data().origin_vn_src.empty() ?
     453          18 :                             fe->data().origin_vn_src :
     454         244 :                             fe->data().source_vn_match;
     455         226 :     const string &dst_vn = !fe->data().origin_vn_dst.empty() ?
     456          10 :                             fe->data().origin_vn_dst :
     457         236 :                             fe->data().dest_vn_match;
     458             : 
     459         226 :     session_endpoint_key.vmi_cfg_name = vmi->cfg_name();
     460         226 :     session_endpoint_key.local_tagset = fe->local_tagset();
     461         226 :     session_endpoint_key.remote_tagset = fe->remote_tagset();
     462         226 :     session_endpoint_key.remote_prefix = fe->RemotePrefix();
     463         226 :     session_endpoint_key.match_policy = fe->fw_policy_name_uuid();
     464         226 :     if (vmi->service_intf_type().empty()) {
     465         226 :         session_endpoint_key.is_si = false;
     466             :     } else {
     467           0 :         session_endpoint_key.is_si= true;
     468             :     }
     469             : 
     470         226 :     if (fe->IsClientFlow()) {
     471          63 :         session_agg_key.local_ip = fe->key().src_addr;
     472          63 :         session_agg_key.server_port = fe->key().dst_port;
     473          63 :         session_key.remote_ip = fe->key().dst_addr;
     474          63 :         session_key.client_port = fe->key().src_port;
     475          63 :         session_endpoint_key.local_vn = src_vn;
     476          63 :         session_endpoint_key.remote_vn = dst_vn;
     477          63 :         session_endpoint_key.is_client_session = true;
     478         163 :     } else if (fe->IsServerFlow()) {
     479             :         /*
     480             :          *  If it is local flow, then reverse flow
     481             :          *  (Ingress + Reverse) will be used to create
     482             :          *  the server side session (Egress + Forward)
     483             :          */
     484         163 :         if (fe->is_flags_set(FlowEntry::LocalFlow)) {
     485          25 :             session_agg_key.local_ip = fe->key().src_addr;
     486          25 :             session_agg_key.server_port = fe->key().src_port;
     487          25 :             session_key.remote_ip = fe->key().dst_addr;
     488          25 :             session_key.client_port = fe->key().dst_port;
     489          25 :             session_endpoint_key.local_vn = src_vn;
     490          25 :             session_endpoint_key.remote_vn = dst_vn;
     491             :         } else {
     492         138 :             session_agg_key.local_ip = fe->key().dst_addr;
     493         138 :             session_agg_key.server_port = fe->key().dst_port;
     494         138 :             session_key.remote_ip = fe->key().src_addr;
     495         138 :             session_key.client_port = fe->key().src_port;
     496         138 :             session_endpoint_key.local_vn = dst_vn;
     497         138 :             session_endpoint_key.remote_vn = src_vn;
     498             :         }
     499         163 :         session_endpoint_key.is_client_session = false;
     500             :     } else {
     501           0 :         return false;
     502             :     }
     503         226 :     session_agg_key.proto = fe->key().protocol;
     504         226 :     session_key.uuid = fe->uuid();
     505         226 :     return true;
     506             : }
     507             : 
     508         452 : void SessionStatsCollector::UpdateSessionFlowStatsInfo(FlowEntry *fe,
     509             :     SessionFlowStatsInfo *session_flow) const {
     510         452 :     session_flow->flow = fe;
     511         452 :     session_flow->gen_id= fe->gen_id();
     512         452 :     session_flow->flow_handle = fe->flow_handle();
     513         452 :     session_flow->uuid = fe->uuid();
     514         452 :     session_flow->total_bytes = 0;
     515         452 :     session_flow->total_packets = 0;
     516         452 : }
     517             : 
     518         226 : void SessionStatsCollector::UpdateSessionStatsInfo(FlowEntry* fe,
     519             :     uint64_t setup_time, SessionStatsInfo *session) const {
     520         226 :     FlowEntry *rfe = fe->reverse_flow_entry();
     521             : 
     522         226 :     session->setup_time = setup_time;
     523         226 :     session->teardown_time = 0;
     524         226 :     session->exported_atleast_once = false;
     525         226 :     UpdateSessionFlowStatsInfo(fe, &session->fwd_flow);
     526         226 :     UpdateSessionFlowStatsInfo(rfe, &session->rev_flow);
     527         226 : }
     528             : 
     529         654 : static void BuildTraceTagList(const TagList &slist, vector<string> *dlist) {
     530         654 :     TagList::const_iterator it = slist.begin();
     531         654 :     while (it != slist.end()) {
     532           0 :         dlist->push_back(integerToString(*it));
     533           0 :         ++it;
     534             :     }
     535         654 : }
     536             : 
     537         327 : static void TraceSession(const string &op, const SessionEndpointKey &ep,
     538             :                          const SessionAggKey &agg, const SessionKey &session,
     539             :                          bool rev_flow_params) {
     540         327 :     SessionTraceInfo info;
     541         327 :     info.vmi = ep.vmi_cfg_name;
     542         327 :     info.local_vn = ep.local_vn;
     543         327 :     info.remote_vn = ep.remote_vn;
     544         327 :     BuildTraceTagList(ep.local_tagset, &info.local_tagset);
     545         327 :     BuildTraceTagList(ep.remote_tagset, &info.remote_tagset);
     546         327 :     info.remote_prefix = ep.remote_prefix;
     547         327 :     info.match_policy = ep.match_policy;
     548         327 :     info.is_si = ep.is_si;
     549         327 :     info.is_client = ep.is_client_session;
     550         327 :     info.local_ip = agg.local_ip.to_string();
     551         327 :     info.server_port = agg.server_port;
     552         327 :     info.protocol = agg.proto;
     553         327 :     info.remote_ip = session.remote_ip.to_string();
     554         327 :     info.client_port = session.client_port;
     555         327 :     info.flow_uuid = to_string(session.uuid);
     556         327 :     SESSION_STATS_TRACE(Trace, op, info, rev_flow_params);
     557         327 : }
     558             : 
     559         230 : void SessionStatsCollector::AddSession(FlowEntry* fe, uint64_t setup_time) {
     560         230 :     SessionAggKey session_agg_key;
     561         230 :     SessionEndpointInfo::SessionAggMap::iterator session_agg_map_iter;
     562         230 :     SessionPreAggInfo session_agg_info;
     563         230 :     SessionStatsInfo session;
     564         230 :     SessionKey session_key;
     565         230 :     SessionPreAggInfo::SessionMap::iterator session_map_iter;
     566         230 :     SessionEndpointInfo  session_endpoint_info = {};
     567         230 :     SessionEndpointKey session_endpoint_key;
     568         230 :     SessionEndpointMap::iterator session_endpoint_map_iter;
     569         230 :     FlowEntry *fe_fwd = fe;
     570             :     bool success;
     571             : 
     572         230 :     if (NULL == fe->reverse_flow_entry()) {
     573           0 :         return;
     574             :     }
     575             : 
     576         230 :     if (!(fe->is_flags_set(FlowEntry::LocalFlow))) {
     577         180 :         if (fe->is_flags_set(FlowEntry::ReverseFlow)) {
     578          90 :             fe_fwd = fe->reverse_flow_entry();
     579             :         }
     580             :     }
     581             : 
     582         230 :     success = GetSessionKey(fe_fwd, session_agg_key, session_key,
     583             :                             session_endpoint_key);
     584         230 :     if (!success) {
     585           4 :         return;
     586             :     }
     587             : 
     588             :     /*
     589             :      * If the flow is part of session endpoint DB then
     590             :      * delete the existing one
     591             :      * Flow add comes for the existing flow for the following cases
     592             :      * - flow uuid changes (add-delete-add : will be compressed)
     593             :      * - any key changes from session endpoint, aggregate or session
     594             :      */
     595         226 :     FlowSessionMap::iterator flow_session_map_iter;
     596         226 :     flow_session_map_iter = flow_session_map_.find(fe_fwd);
     597         226 :     if (flow_session_map_iter != flow_session_map_.end()) {
     598             : 
     599         119 :         FlowToSessionMap &flow_to_session_map = flow_session_map_iter->second;
     600             :         FlowToSessionMap rhs_flow_to_session_map(session_key,
     601             :                                                  session_agg_key,
     602         119 :                                                  session_endpoint_key);
     603         119 :         if (!(flow_to_session_map.IsEqual(rhs_flow_to_session_map))) {
     604          24 :             DeleteSession(fe_fwd, flow_to_session_map.session_key().uuid,
     605             :                           GetCurrentTime(), NULL);
     606             :         }
     607         119 :     }
     608             : 
     609         226 :     TraceSession("Add", session_endpoint_key, session_agg_key, session_key,
     610             :                  false);
     611         226 :     UpdateSessionStatsInfo(fe_fwd, setup_time, &session);
     612             : 
     613         226 :     session_endpoint_map_iter = session_endpoint_map_.find(
     614             :                                             session_endpoint_key);
     615         226 :     if (session_endpoint_map_iter == session_endpoint_map_.end()) {
     616          35 :         session_agg_info.session_map_.insert(make_pair(session_key, session));
     617          35 :         session_endpoint_info.session_agg_map_.insert(
     618          70 :                                 make_pair(session_agg_key, session_agg_info));
     619          35 :         session_endpoint_map_.insert(make_pair(session_endpoint_key,
     620             :                                                 session_endpoint_info));
     621          35 :         AddFlowToSessionMap(fe_fwd, session_key, session_agg_key,
     622             :                             session_endpoint_key);
     623             :     } else {
     624         191 :         session_agg_map_iter = session_endpoint_map_iter->
     625         191 :                                         second.session_agg_map_.find(
     626             :                                                         session_agg_key);
     627         191 :         if (session_agg_map_iter ==
     628         382 :                 session_endpoint_map_iter->second.session_agg_map_.end()) {
     629          56 :             session_agg_info.session_map_.insert(make_pair(session_key, session));
     630         112 :             session_endpoint_map_iter->second.session_agg_map_.insert(
     631         112 :                                 make_pair(session_agg_key, session_agg_info));
     632          56 :             AddFlowToSessionMap(fe_fwd, session_key, session_agg_key,
     633             :                                 session_endpoint_key);
     634             :         } else {
     635             :             session_map_iter =
     636         135 :                 session_agg_map_iter->second.session_map_.find(session_key);
     637         135 :             if (session_map_iter ==
     638         270 :                     session_agg_map_iter->second.session_map_.end()) {
     639          20 :                 session_agg_map_iter->second.session_map_.insert(
     640          20 :                                         make_pair(session_key, session));
     641          10 :                 AddFlowToSessionMap(fe_fwd, session_key, session_agg_key,
     642             :                                     session_endpoint_key);
     643             :             } else {
     644             :                 /*
     645             :                  * existing flow should match with the incoming add flow
     646             :                  */
     647         125 :         assert(session.fwd_flow.uuid == fe_fwd->uuid());
     648             :             }
     649             :         }
     650             :     }
     651         242 : }
     652             : 
     653         168 : void SessionStatsCollector::DeleteSession(FlowEntry* fe,
     654             :                                           const boost::uuids::uuid &del_uuid,
     655             :                                           uint64_t teardown_time,
     656             :                                           const RevFlowDepParams *params) {
     657         168 :     SessionAggKey session_agg_key;
     658         168 :     SessionEndpointInfo::SessionAggMap::iterator session_agg_map_iter;
     659         168 :     SessionPreAggInfo  session_agg_info;
     660         168 :     SessionKey session_key;
     661         168 :     SessionPreAggInfo::SessionMap::iterator session_map_iter;
     662         168 :     SessionEndpointInfo  session_endpoint_info;
     663         168 :     SessionEndpointKey session_endpoint_key;
     664         168 :     SessionEndpointMap::iterator session_endpoint_map_iter;
     665         168 :     bool read_flow = true;
     666             : 
     667         168 :     if (del_uuid != fe->uuid()) {
     668           3 :         read_flow = false;
     669             :     }
     670             : 
     671             :     /*
     672             :      * If the given flow uuid is different from the existing one
     673             :      * then ignore the read from flow
     674             :      */
     675         168 :     FlowSessionMap::iterator flow_session_map_iter;
     676             : 
     677         168 :     flow_session_map_iter = flow_session_map_.find(fe);
     678         168 :     if (flow_session_map_iter != flow_session_map_.end()) {
     679         101 :         if (del_uuid != flow_session_map_iter->second.session_key().uuid) {
     680             :             /* We had never seen ADD for del_uuid, ignore delete request. This
     681             :              * can happen when the following events occur
     682             :              * 1. Add with UUID x
     683             :              * 2. Delete with UUID x
     684             :              * 3. Add with UUID y
     685             :              * 4. Delete with UUID y
     686             :              * When events 2 and 3 are suppressed and we receive only 1 and 4
     687             :              * In this case initiated delete for entry with UUID x */
     688           2 :             read_flow = false;
     689             :             /* Reset params because they correspond to entry with UUID y */
     690           2 :             params = NULL;
     691             :         }
     692         101 :         session_endpoint_key = flow_session_map_iter->second.session_endpoint_key();
     693         101 :         session_agg_key = flow_session_map_iter->second.session_agg_key();
     694         101 :         session_key = flow_session_map_iter->second.session_key();
     695             :     } else {
     696          67 :         return;
     697             :     }
     698         101 :     if (params && params->action_info_.action == 0) {
     699          19 :         params = NULL;
     700             :     }
     701             : 
     702         101 :     bool params_valid = true;
     703         101 :     if (params == NULL) {
     704          45 :         params_valid = false;
     705             :     }
     706             : 
     707         101 :     TraceSession("Del", session_endpoint_key, session_agg_key, session_key,
     708             :                  params_valid);
     709         101 :     session_endpoint_map_iter = session_endpoint_map_.find(
     710             :                                             session_endpoint_key);
     711         101 :     if (session_endpoint_map_iter != session_endpoint_map_.end()) {
     712         101 :         session_agg_map_iter = session_endpoint_map_iter->
     713         101 :                                         second.session_agg_map_.find(
     714             :                                                         session_agg_key);
     715         101 :         if (session_agg_map_iter !=
     716         202 :                 session_endpoint_map_iter->second.session_agg_map_.end()) {
     717             :             session_map_iter =
     718         101 :                 session_agg_map_iter->second.session_map_.find(session_key);
     719         101 :             if (session_map_iter !=
     720         202 :                     session_agg_map_iter->second.session_map_.end()) {
     721             :                 /*
     722             :                  * Process the stats collector
     723             :                  */
     724         101 :                 session_map_iter->second.teardown_time = teardown_time;
     725         101 :                 session_map_iter->second.deleted = true;
     726             :                 /* Don't read stats for evicted flow, during delete */
     727         101 :                 if (!session_map_iter->second.evicted) {
     728         101 :                     SessionStatsChangedUnlocked(session_map_iter,
     729         101 :                         &session_map_iter->second.del_stats);
     730             :                 }
     731         101 :                 if (read_flow) {
     732          96 :                     CopyFlowInfo(session_map_iter->second, params);
     733             :                 }
     734             : 
     735         101 :                 assert(session_map_iter->second.fwd_flow.flow.get() == fe);
     736         101 :                 DeleteFlowToSessionMap(fe);
     737         101 :                 session_map_iter->second.fwd_flow.flow = NULL;
     738         101 :                 session_map_iter->second.rev_flow.flow = NULL;
     739             :             }
     740             :         }
     741             :     }
     742         302 : }
     743             : 
     744           0 : void SessionStatsCollector::EvictedSessionStatsUpdate(const FlowEntryPtr &flow,
     745             :                                                 uint32_t bytes,
     746             :                                                 uint32_t packets,
     747             :                                                 uint32_t oflow_bytes,
     748             :                                                 const boost::uuids::uuid &u) {
     749           0 :     FlowSessionMap::iterator flow_session_map_iter;
     750           0 :     SessionInfo session_info;
     751           0 :     SessionIpPort session_key;
     752           0 :     SessionAggInfo session_agg_info;
     753           0 :     SessionIpPortProtocol session_agg_key;
     754           0 :     SessionEndpointMap::iterator session_ep_map_iter;
     755           0 :     SessionEndpointInfo::SessionAggMap::iterator session_agg_map_iter;
     756           0 :     SessionPreAggInfo::SessionMap::iterator session_map_iter;
     757             : 
     758             :     /* TODO: Evicted msg coming for reverse flow. We currently don't have
     759             :      * mapping from reverse_flow to flow_session_map */
     760           0 :     flow_session_map_iter = flow_session_map_.find(flow.get());
     761           0 :     if (flow_session_map_iter == flow_session_map_.end()) {
     762           0 :         return;
     763             :     }
     764             : 
     765           0 :     if (flow_session_map_iter->second.session_key().uuid != u) {
     766           0 :         return;
     767             :     }
     768             : 
     769           0 :     SessionEndpointKey session_db_ep_key = flow_session_map_iter->second.session_endpoint_key();
     770           0 :     SessionAggKey session_db_agg_key = flow_session_map_iter->second.session_agg_key();
     771           0 :     SessionKey session_db_key = flow_session_map_iter->second.session_key();
     772             : 
     773           0 :     session_ep_map_iter = session_endpoint_map_.find(session_db_ep_key);
     774           0 :     if (session_ep_map_iter != session_endpoint_map_.end()) {
     775           0 :         session_agg_map_iter = session_ep_map_iter->
     776           0 :                                         second.session_agg_map_.find(
     777             :                                                         session_db_agg_key);
     778           0 :         if (session_agg_map_iter !=
     779           0 :                 session_ep_map_iter->second.session_agg_map_.end()) {
     780             :             session_map_iter =
     781           0 :                 session_agg_map_iter->second.session_map_.find(session_db_key);
     782           0 :             if (session_map_iter !=
     783           0 :                     session_agg_map_iter->second.session_map_.end()) {
     784             :                 /*
     785             :                  * update the latest statistics
     786             :                  */
     787           0 :                 SessionFlowStatsInfo &session_flow = session_map_iter->second.fwd_flow;
     788           0 :                 uint64_t k_bytes, total_bytes, diff_bytes = 0;
     789           0 :                 uint64_t k_packets, total_packets, diff_packets = 0;
     790           0 :                 k_bytes = FlowStatsCollector::GetFlowStats((oflow_bytes & 0xFFFF),
     791             :                                                            bytes);
     792           0 :                 k_packets = FlowStatsCollector::GetFlowStats((oflow_bytes & 0xFFFF0000),
     793             :                                                              packets);
     794           0 :                 total_bytes = GetUpdatedSessionFlowBytes(session_flow.total_bytes,
     795             :                                                          k_bytes);
     796           0 :                 total_packets = GetUpdatedSessionFlowPackets(session_flow.total_packets,
     797             :                                                              k_packets);
     798           0 :                 diff_bytes = total_bytes - session_flow.total_bytes;
     799           0 :                 diff_packets = total_packets - session_flow.total_packets;
     800           0 :                 session_flow.total_bytes = total_bytes;
     801           0 :                 session_flow.total_packets = total_packets;
     802             : 
     803           0 :                 SessionStatsParams &estats = session_map_iter->second.
     804           0 :                     evict_stats;
     805           0 :                 session_map_iter->second.evicted = true;
     806           0 :                 estats.fwd_flow.valid = true;
     807           0 :                 estats.fwd_flow.diff_bytes = diff_bytes;
     808           0 :                 estats.fwd_flow.diff_packets = diff_packets;
     809             :             }
     810             :         }
     811             :     }
     812           0 : }
     813             : 
     814         101 : void SessionStatsCollector::AddFlowToSessionMap(FlowEntry *fe,
     815             :                                                 SessionKey session_key,
     816             :                                                 SessionAggKey session_agg_key,
     817             :                                                 SessionEndpointKey session_endpoint_key) {
     818             :     FlowToSessionMap flow_to_session_map(session_key, session_agg_key,
     819         101 :                                          session_endpoint_key);
     820             :     std::pair<FlowSessionMap::iterator, bool> ret =
     821         101 :         flow_session_map_.insert(make_pair(fe, flow_to_session_map));
     822         101 :     if (ret.second == false) {
     823           0 :         FlowToSessionMap &prev = ret.first->second;
     824           0 :         assert(prev.session_key().uuid == fe->uuid());
     825             :     }
     826         101 : }
     827             : 
     828         101 : void SessionStatsCollector::DeleteFlowToSessionMap(FlowEntry *fe) {
     829         101 :     FlowSessionMap::iterator flow_session_map_iter;
     830         101 :     flow_session_map_iter = flow_session_map_.find(fe);
     831         101 :     if (flow_session_map_iter != flow_session_map_.end()) {
     832         101 :         flow_session_map_.erase(flow_session_map_iter);
     833             :     }
     834         101 : }
     835             : 
     836           0 : int SessionStatsCollector::ComputeSloRate(int rate, SecurityLoggingObject *slo)
     837             :     const {
     838             :     /* If rate is not configured, it will have -1 as value
     839             :      * -1 as value. In this case, pick the rate from SLO */
     840           0 :     if (rate == -1) {
     841           0 :         rate = slo->rate();
     842             :     }
     843           0 :     return rate;
     844             : }
     845             : 
     846           0 : void SessionStatsCollector::UpdateSloStateRules(SecurityLoggingObject *slo,
     847             :                                                 SessionSloState *state) {
     848           0 :     vector<autogen::SecurityLoggingObjectRuleEntryType>::const_iterator it;
     849           0 :     it = slo->rules().begin();
     850           0 :     while (it != slo->rules().end()) {
     851           0 :         state->UpdateSessionSloStateRuleEntry(it->rule_uuid, it->rate);
     852           0 :         it++;
     853             :     }
     854             : 
     855           0 :     SloRuleList::const_iterator acl_it = slo->firewall_policy_list().begin();
     856           0 :     while (acl_it != slo->firewall_policy_list().end()) {
     857           0 :         AclKey key(acl_it->uuid_);
     858           0 :         AclDBEntry *acl = static_cast<AclDBEntry *>(agent_uve_->agent()->
     859           0 :                         acl_table()->FindActiveEntry(&key));
     860           0 :         if (acl) {
     861           0 :             int index = 0;
     862           0 :             int rate = ComputeSloRate(acl_it->rate_, slo);
     863           0 :             const AclEntry *ae = acl->GetAclEntryAtIndex(index);
     864           0 :             while (ae != NULL) {
     865           0 :                 state->UpdateSessionSloStateRuleEntry(ae->uuid(), rate);
     866           0 :                 index++;
     867           0 :                 ae = acl->GetAclEntryAtIndex(index);
     868             :             }
     869             :         }
     870           0 :         acl_it++;
     871           0 :     }
     872             : 
     873           0 :     SloRuleList::const_iterator fw_rule_it;
     874           0 :     fw_rule_it = slo->firewall_rule_list().begin();
     875           0 :     while (fw_rule_it != slo->firewall_rule_list().end()) {
     876           0 :         const SloRuleInfo &item = *fw_rule_it;
     877           0 :         int rate = ComputeSloRate(item.rate_, slo);
     878           0 :         state->UpdateSessionSloStateRuleEntry(to_string(item.uuid_), rate);
     879           0 :         fw_rule_it++;
     880             :     }
     881             : 
     882           0 : }
     883             : 
     884           0 : void SessionStatsCollector::SloNotify(DBTablePartBase *partition,
     885             :                                       DBEntryBase *e) {
     886           0 :     SecurityLoggingObject *slo = static_cast<SecurityLoggingObject *>(e);
     887             :     SessionSloState *state =
     888           0 :         static_cast<SessionSloState *>(slo->GetState(partition->parent(),
     889             :                                                      slo_listener_id_));
     890           0 :     if (slo->IsDeleted()) {
     891           0 :         if (!state)
     892           0 :             return;
     893           0 :         slo->ClearState(partition->parent(), slo_listener_id_);
     894           0 :         delete state;
     895           0 :         return;
     896             :     }
     897             : 
     898           0 :     if (!state) {
     899           0 :         state = new SessionSloState();
     900           0 :         slo->SetState(slo->get_table(), slo_listener_id_, state);
     901             :     }
     902           0 :     UpdateSloStateRules(slo, state);
     903             : }
     904             : 
     905           0 : void SessionStatsCollector::AddSessionSloRuleEntry(const std::string &uuid,
     906             :                                                    int rate,
     907             :                                                    SecurityLoggingObject *slo,
     908             :                                                    SessionSloRuleMap *slo_rule_map) {
     909           0 :     SessionSloRuleEntry slo_rule_entry(rate, slo->uuid());
     910           0 :     std::pair<SessionSloRuleMap::iterator, bool> ret;
     911           0 :     ret = slo_rule_map->insert(make_pair(uuid,
     912           0 :                                           slo_rule_entry));
     913           0 : }
     914             : 
     915           0 : void SessionStatsCollector::AddSloRules(
     916             :         const std::vector<autogen::SecurityLoggingObjectRuleEntryType> &list,
     917             :         SecurityLoggingObject *slo,
     918             :         SessionSloRuleMap *slo_rule_map) {
     919           0 :     vector<autogen::SecurityLoggingObjectRuleEntryType>::const_iterator it;
     920           0 :     it = list.begin();
     921           0 :     while (it != list.end()) {
     922           0 :         AddSessionSloRuleEntry(it->rule_uuid, it->rate, slo, slo_rule_map);
     923           0 :         it++;
     924             :     }
     925           0 : }
     926             : 
     927           0 : void SessionStatsCollector::AddSloFirewallPolicies(SecurityLoggingObject *slo,
     928             :                                                    SessionSloRuleMap *r_map) {
     929           0 :     const SloRuleList &list = slo->firewall_policy_list();
     930           0 :     SloRuleList::const_iterator acl_it = list.begin();
     931           0 :     while (acl_it != list.end()) {
     932           0 :         AclKey key(acl_it->uuid_);
     933           0 :         AclDBEntry *acl = static_cast<AclDBEntry *>(agent_uve_->agent()->
     934           0 :                         acl_table()->FindActiveEntry(&key));
     935           0 :         if (acl) {
     936           0 :             int index = 0;
     937           0 :             const AclEntry *ae = acl->GetAclEntryAtIndex(index);
     938           0 :             int rate = ComputeSloRate(acl_it->rate_, slo);
     939           0 :             while (ae != NULL) {
     940           0 :                 AddSessionSloRuleEntry(ae->uuid(), rate, slo, r_map);
     941           0 :                 index++;
     942           0 :                 ae = acl->GetAclEntryAtIndex(index);
     943             :             }
     944             :         }
     945           0 :         acl_it++;
     946           0 :     }
     947           0 : }
     948             : 
     949           0 : void SessionStatsCollector::AddSloFirewallRules(SecurityLoggingObject *slo,
     950             :                                                 SessionSloRuleMap *rule_map) {
     951           0 :     const SloRuleList &list = slo->firewall_rule_list();
     952           0 :     SloRuleList::const_iterator it = list.begin();
     953           0 :     while (it != list.end()) {
     954           0 :         int rate = ComputeSloRate(it->rate_, slo);
     955           0 :         AddSessionSloRuleEntry(to_string(it->uuid_), rate, slo, rule_map);
     956           0 :         it++;
     957             :     }
     958           0 : }
     959             : 
     960           0 : void SessionStatsCollector::AddSloEntryRules(SecurityLoggingObject *slo,
     961             :                                              SessionSloRuleMap *slo_rule_map) {
     962           0 :     AddSloRules(slo->rules(), slo, slo_rule_map);
     963           0 :     AddSloFirewallPolicies(slo, slo_rule_map);
     964           0 :     AddSloFirewallRules(slo, slo_rule_map);
     965           0 : }
     966             : 
     967           0 : void SessionStatsCollector::AddSloEntry(const boost::uuids::uuid &uuid,
     968             :                                        SessionSloRuleMap *slo_rule_map) {
     969           0 :     SecurityLoggingObjectKey slo_key(uuid);
     970           0 :     SecurityLoggingObject *slo = static_cast<SecurityLoggingObject *>
     971           0 :         (agent_uve_->agent()->slo_table()->FindActiveEntry(&slo_key));
     972           0 :     if (slo) {
     973           0 :         if (slo->status()) {
     974           0 :             AddSloEntryRules(slo, slo_rule_map);
     975             :         }
     976             :     }
     977           0 : }
     978             : 
     979           0 : void SessionStatsCollector::AddSloList(const UuidList &slo_list,
     980             :                                        SessionSloRuleMap *slo_rule_map) {
     981           0 :     UuidList::const_iterator sit = slo_list.begin();
     982           0 :     while (sit != slo_list.end()) {
     983           0 :         AddSloEntry(*sit, slo_rule_map);
     984           0 :         sit++;
     985             :     }
     986           0 : }
     987             : 
     988           0 : void SessionStatsCollector::MakeSloList(const FlowEntry *fe,
     989             :                                         SessionSloRuleMap *vmi_session_slo_rule_map,
     990             :                                         SessionSloRuleMap *vn_session_slo_rule_map) {
     991           0 :     if (fe == NULL) {
     992           0 :         return;
     993             :     }
     994           0 :     const Interface *itf = fe->intf_entry();
     995           0 :     if (!itf) {
     996           0 :         return;
     997             :     }
     998           0 :     if (itf->type() != Interface::VM_INTERFACE) {
     999           0 :         return;
    1000             :     }
    1001           0 :     const VmInterface *vmi = static_cast<const VmInterface *>(itf);
    1002           0 :     AddSloList(vmi->slo_list(), vmi_session_slo_rule_map);
    1003           0 :     if (vmi->vn()) {
    1004           0 :         AddSloList(vmi->vn()->slo_list(), vn_session_slo_rule_map);
    1005             :     }
    1006           0 :     return;
    1007             : }
    1008             : 
    1009           0 : void SessionStatsCollector::BuildSloList(
    1010             :                                 const SessionStatsInfo    &stats_info,
    1011             :                                 const FlowEntry *fe,
    1012             :                                 SessionSloRuleMap *global_session_slo_rule_map,
    1013             :                                 SessionSloRuleMap *vmi_session_slo_rule_map,
    1014             :                                 SessionSloRuleMap *vn_session_slo_rule_map) {
    1015             : 
    1016           0 :     vmi_session_slo_rule_map->clear();
    1017           0 :     vn_session_slo_rule_map->clear();
    1018           0 :     global_session_slo_rule_map->clear();
    1019             : 
    1020           0 :     if (agent_uve_->agent()->oper_db()->global_vrouter()->slo_uuid() !=
    1021           0 :         boost::uuids::nil_uuid()) {
    1022           0 :         AddSloEntry(
    1023           0 :                 agent_uve_->agent()->oper_db()->global_vrouter()->slo_uuid(),
    1024             :                 global_session_slo_rule_map);
    1025             :     }
    1026             : 
    1027           0 :     if (stats_info.deleted) {
    1028           0 :         AddSloList(stats_info.export_info.vmi_slo_list, vmi_session_slo_rule_map);
    1029           0 :         AddSloList(stats_info.export_info.vn_slo_list, vn_session_slo_rule_map);
    1030             :     } else {
    1031           0 :         MakeSloList(fe, vmi_session_slo_rule_map, vn_session_slo_rule_map);
    1032             :     }
    1033           0 : }
    1034             : 
    1035           0 : bool SessionStatsCollector::UpdateSloMatchRuleEntry(
    1036             :                             const boost::uuids::uuid &slo_uuid,
    1037             :                             const std::string &match_uuid,
    1038             :                             bool *match) {
    1039           0 :     SecurityLoggingObjectKey slo_key(slo_uuid);
    1040           0 :     SecurityLoggingObject *slo = static_cast<SecurityLoggingObject *>
    1041           0 :         (agent_uve_->agent()->slo_table()->FindActiveEntry(&slo_key));
    1042           0 :     if (slo) {
    1043             :         SessionSloState *state =
    1044           0 :             static_cast<SessionSloState *>(slo->GetState(agent_uve_->agent()->slo_table(),
    1045             :                                                          slo_listener_id_));
    1046           0 :         if (state) {
    1047           0 :             return state->UpdateSessionSloStateRuleRefCount(match_uuid, match);
    1048             :         }
    1049             :     }
    1050           0 :     *match = false;
    1051           0 :     return false;
    1052           0 : }
    1053             : 
    1054           0 : bool SessionStatsCollector::CheckPolicyMatch(const SessionSloRuleMap &map,
    1055             :                                              const std::string &policy_uuid,
    1056             :                                              const bool &deleted_flag,
    1057             :                                              bool *match,
    1058             :                                              const bool &exported_once) {
    1059           0 :     SessionSloRuleMap::const_iterator it;
    1060           0 :     if (!policy_uuid.empty()) {
    1061           0 :         it = map.find(policy_uuid);
    1062           0 :         if (it != map.end()) {
    1063             :             /* Always logging tear down session, which is exported atleast once
    1064             :              * earlier will be logged other tear down sessions will be reported
    1065             :              * with SLO rate checking
    1066             :              */
    1067           0 :             if (deleted_flag && exported_once) {
    1068           0 :                 *match = true;
    1069           0 :                 return true;
    1070             :             }
    1071           0 :             return UpdateSloMatchRuleEntry(it->second.slo_uuid, policy_uuid, match);
    1072             :         }
    1073             :     }
    1074           0 :     *match = false;
    1075           0 :     return false;
    1076             : }
    1077             : 
    1078           0 : bool SessionStatsCollector::FindSloMatchRule(const SessionSloRuleMap &map,
    1079             :                                              const std::string &fw_policy_uuid,
    1080             :                                              const std::string &nw_policy_uuid,
    1081             :                                              const std::string &sg_policy_uuid,
    1082             :                                              const bool &deleted_flag,
    1083             :                                              bool *match,
    1084             :                                              const bool &exported_once) {
    1085           0 :     SessionSloRuleMap::const_iterator it;
    1086           0 :     bool fw_logged = false, nw_logged = false, sg_logged = false;
    1087           0 :     bool fw_match = false, nw_match = false, sg_match = false;
    1088             : 
    1089           0 :     fw_logged = CheckPolicyMatch(map, fw_policy_uuid, deleted_flag,
    1090             :                                  &fw_match, exported_once);
    1091           0 :     nw_logged = CheckPolicyMatch(map, nw_policy_uuid, deleted_flag,
    1092             :                                  &nw_match, exported_once);
    1093           0 :     sg_logged = CheckPolicyMatch(map, sg_policy_uuid, deleted_flag,
    1094             :                                  &sg_match, exported_once);
    1095             : 
    1096           0 :     if (fw_match || nw_match || sg_match) {
    1097           0 :         *match = true;
    1098             :     } else {
    1099           0 :         *match = false;
    1100             :     }
    1101             : 
    1102           0 :     if (fw_logged || nw_logged || sg_logged) {
    1103           0 :         return true;
    1104             :     }
    1105           0 :     return false;
    1106             : }
    1107             : 
    1108           0 : bool SessionStatsCollector::MatchSloForFlow(
    1109             :                             const SessionStatsInfo    &stats_info,
    1110             :                             const FlowEntry *fe,
    1111             :                             const std::string &fw_policy_uuid,
    1112             :                             const std::string &nw_policy_uuid,
    1113             :                             const std::string &sg_policy_uuid,
    1114             :                             const bool &deleted_flag,
    1115             :                             bool *logged,
    1116             :                             const bool &exported_once) {
    1117             : 
    1118             :     bool is_vmi_slo_logged, is_vn_slo_logged, is_global_slo_logged;
    1119             :     bool vmi_slo_match, vn_slo_match, global_slo_match;
    1120           0 :     SessionSloRuleMap vmi_session_slo_rule_map;
    1121           0 :     SessionSloRuleMap vn_session_slo_rule_map;
    1122           0 :     SessionSloRuleMap global_session_slo_rule_map;
    1123             : 
    1124             :     /*
    1125             :      * Get the list of slos need to be matched for the given flow
    1126             :      */
    1127           0 :     BuildSloList(stats_info, fe,
    1128             :                  &global_session_slo_rule_map,
    1129             :                  &vmi_session_slo_rule_map,
    1130             :                  &vn_session_slo_rule_map);
    1131             :     /*
    1132             :      * Match each type of policy for the given flow against the slo list
    1133             :      */
    1134             : 
    1135           0 :     is_vmi_slo_logged = FindSloMatchRule(vmi_session_slo_rule_map,
    1136             :                                          fw_policy_uuid,
    1137             :                                          nw_policy_uuid,
    1138             :                                          sg_policy_uuid,
    1139             :                                          deleted_flag,
    1140             :                                          &vmi_slo_match,
    1141             :                                          exported_once);
    1142             : 
    1143           0 :     is_vn_slo_logged = FindSloMatchRule(vn_session_slo_rule_map,
    1144             :                                         fw_policy_uuid,
    1145             :                                         nw_policy_uuid,
    1146             :                                         sg_policy_uuid,
    1147             :                                         deleted_flag,
    1148             :                                         &vn_slo_match,
    1149             :                                         exported_once);
    1150             : 
    1151           0 :     is_global_slo_logged = FindSloMatchRule(global_session_slo_rule_map,
    1152             :                                             fw_policy_uuid,
    1153             :                                             nw_policy_uuid,
    1154             :                                             sg_policy_uuid,
    1155             :                                             deleted_flag,
    1156             :                                             &global_slo_match,
    1157             :                                             exported_once);
    1158           0 :     if ((is_vmi_slo_logged) ||
    1159           0 :         (is_vn_slo_logged) ||
    1160             :         (is_global_slo_logged)) {
    1161           0 :         *logged = true;
    1162             :     }
    1163           0 :     if (vmi_slo_match || vn_slo_match || global_slo_match) {
    1164           0 :          return true;
    1165             :     } else {
    1166           0 :         return false;
    1167             :     }
    1168           0 : }
    1169             : 
    1170           0 : void SessionStatsCollector::GetPolicyIdFromDeletedFlow(
    1171             :                             const SessionFlowExportInfo &flow_info,
    1172             :                             std::string &fw_policy_uuid,
    1173             :                             std::string &nw_policy_uuid,
    1174             :                             std::string &sg_policy_uuid) {
    1175           0 :     fw_policy_uuid = flow_info.aps_rule_uuid;
    1176           0 :     sg_policy_uuid = flow_info.sg_rule_uuid;
    1177           0 :     nw_policy_uuid = flow_info.nw_ace_uuid;
    1178           0 :     return;
    1179             : }
    1180             : 
    1181           0 : void SessionStatsCollector::GetPolicyIdFromFlow(
    1182             :                             const FlowEntry *fe,
    1183             :                             std::string &fw_policy_uuid,
    1184             :                             std::string &nw_policy_uuid,
    1185             :                             std::string &sg_policy_uuid) {
    1186           0 :     fw_policy_uuid = fe->fw_policy_uuid();
    1187           0 :     sg_policy_uuid = fe->sg_rule_uuid();
    1188           0 :     nw_policy_uuid = fe->nw_ace_uuid();
    1189           0 :     return;
    1190             : }
    1191             : 
    1192           0 : bool SessionStatsCollector::FlowLogging(
    1193             :                             const SessionStatsInfo    &stats_info,
    1194             :                             const FlowEntry *fe,
    1195             :                             bool  *logged,
    1196             :                             const bool  &exported_once) {
    1197             : 
    1198           0 :     bool matched = false, deleted_flag=false;
    1199           0 :     std::string fw_policy_uuid = "", nw_policy_uuid = "", sg_policy_uuid = "";
    1200             : 
    1201           0 :     GetPolicyIdFromFlow(fe,
    1202             :                         fw_policy_uuid,
    1203             :                         nw_policy_uuid,
    1204             :                         sg_policy_uuid);
    1205             : 
    1206           0 :     matched = MatchSloForFlow(stats_info,
    1207             :                               fe,
    1208             :                               fw_policy_uuid,
    1209             :                               nw_policy_uuid,
    1210             :                               sg_policy_uuid,
    1211             :                               deleted_flag,
    1212             :                               logged,
    1213             :                               exported_once);
    1214             : 
    1215           0 :     return matched;
    1216           0 : }
    1217             : 
    1218           0 : bool SessionStatsCollector::DeletedFlowLogging(
    1219             :                             const SessionStatsInfo    &stats_info,
    1220             :                             const SessionFlowExportInfo &flow_info,
    1221             :                             bool  *logged,
    1222             :                             const bool  &exported_once) {
    1223             : 
    1224           0 :     bool matched = false, deleted_flag = true;
    1225           0 :     std::string fw_policy_uuid = "", nw_policy_uuid = "", sg_policy_uuid = "";
    1226             : 
    1227           0 :     GetPolicyIdFromDeletedFlow(flow_info,
    1228             :                                fw_policy_uuid,
    1229             :                                nw_policy_uuid,
    1230             :                                sg_policy_uuid);
    1231             : 
    1232           0 :     matched = MatchSloForFlow(stats_info,
    1233             :                               NULL,
    1234             :                               fw_policy_uuid,
    1235             :                               nw_policy_uuid,
    1236             :                               sg_policy_uuid,
    1237             :                               deleted_flag,
    1238             :                               logged,
    1239             :                               exported_once);
    1240             : 
    1241           0 :     return matched;
    1242           0 : }
    1243             : 
    1244           0 : bool SessionStatsCollector::HandleDeletedFlowLogging(
    1245             :                             const SessionStatsInfo    &stats_info) {
    1246             : 
    1247           0 :     bool logged = false;
    1248           0 :     const SessionExportInfo &info = stats_info.export_info;
    1249             : 
    1250             :     /*
    1251             :      * Deleted flow need to to be just checked whether SLO rules matched
    1252             :      * If SLO is macthed, it should be logged irrespective of the rate
    1253             :      */
    1254           0 :     if (DeletedFlowLogging(stats_info,
    1255           0 :                            info.fwd_flow,
    1256             :                            &logged,
    1257           0 :                            stats_info.exported_atleast_once)) {
    1258           0 :         CheckFlowLogging(logged);
    1259           0 :     } else if (DeletedFlowLogging(stats_info,
    1260           0 :                                   info.rev_flow,
    1261             :                                   &logged,
    1262           0 :                                   stats_info.exported_atleast_once)) {
    1263           0 :         CheckFlowLogging(logged);
    1264             :     }
    1265           0 :     return false;
    1266             : }
    1267             : 
    1268           0 : bool SessionStatsCollector::HandleFlowLogging(
    1269             :                             const SessionStatsInfo    &stats_info) {
    1270           0 :     bool logged = false;
    1271             : 
    1272             :     /*
    1273             :      * FWD and REV flow of the Session need to be checked for SLO
    1274             :      * separately. If FWD flow matches or logged then rev flow
    1275             :      * is not required to check for SLO match.
    1276             :      * REV flow will be checked for SLO only when FWD flow
    1277             :      * is not matched for the SLO, since SLO is per session
    1278             :      */
    1279             : 
    1280           0 :     if (FlowLogging(stats_info,
    1281           0 :                     stats_info.fwd_flow.flow.get(),
    1282             :                     &logged,
    1283           0 :                     stats_info.exported_atleast_once)) {
    1284           0 :         CheckFlowLogging(logged);
    1285           0 :     } else if (FlowLogging(stats_info,
    1286           0 :                            stats_info.rev_flow.flow.get(),
    1287             :                            &logged,
    1288           0 :                            stats_info.exported_atleast_once)) {
    1289           0 :         CheckFlowLogging(logged);
    1290             :     }
    1291           0 :     return false;
    1292             : }
    1293             : 
    1294          57 : bool SessionStatsCollector::CheckSessionLogging(
    1295             :                             const SessionStatsInfo    &stats_info) {
    1296             : 
    1297          57 :     if (!agent_uve_->agent()->global_slo_status()) {
    1298             :         /* SLO is not enabled */
    1299          57 :         flow_stats_manager_->session_global_slo_logging_drops_++;
    1300          57 :         return false;
    1301             :     }
    1302             : 
    1303             :     /*
    1304             :      * Deleted flow will be logged if SLO is configured.
    1305             :      * Normal case will be logged only when there is a change in the
    1306             :      * stats. If there is no change in the session stats, it will
    1307             :      * not be considered to SLO match and rate. This will avoid logging
    1308             :      * of each session at least once. Also, idle session will not be
    1309             :      * considered for the rate count
    1310             :      */
    1311             : 
    1312           0 :     if (stats_info.deleted) {
    1313           0 :         if(HandleDeletedFlowLogging(stats_info)) {
    1314           0 :             return true;
    1315             :         }
    1316           0 :     } else if(HandleFlowLogging(stats_info)) {
    1317           0 :         return true;
    1318             :     }
    1319             : 
    1320           0 :     flow_stats_manager_->session_slo_logging_drops_++;
    1321           0 :     return false;
    1322             : }
    1323             : 
    1324         103 : uint64_t SessionStatsCollector::GetUpdatedSessionFlowBytes(uint64_t info_bytes,
    1325             :                                                  uint64_t k_flow_bytes) const {
    1326         103 :     uint64_t oflow_bytes = 0xffff000000000000ULL & info_bytes;
    1327         103 :     uint64_t old_bytes = 0x0000ffffffffffffULL & info_bytes;
    1328         103 :     if (old_bytes > k_flow_bytes) {
    1329           0 :         oflow_bytes += 0x0001000000000000ULL;
    1330             :     }
    1331         103 :     return (oflow_bytes |= k_flow_bytes);
    1332             : }
    1333             : 
    1334         103 : uint64_t SessionStatsCollector::GetUpdatedSessionFlowPackets(
    1335             :                                                   uint64_t info_packets,
    1336             :                                                   uint64_t k_flow_pkts) const {
    1337         103 :     uint64_t oflow_pkts = 0xffffff0000000000ULL & info_packets;
    1338         103 :     uint64_t old_pkts = 0x000000ffffffffffULL & info_packets;
    1339         103 :     if (old_pkts > k_flow_pkts) {
    1340           0 :         oflow_pkts += 0x0000010000000000ULL;
    1341             :     }
    1342         103 :     return (oflow_pkts |= k_flow_pkts);
    1343             : }
    1344             : 
    1345         136 : void SessionStatsCollector::CopyFlowInfoInternal(SessionFlowExportInfo *info,
    1346             :                                                  const boost::uuids::uuid &u,
    1347             :                                                  FlowEntry *fe) const {
    1348         136 :     if (fe->uuid() != u) {
    1349           0 :         return;
    1350             :     }
    1351         136 :     FlowTable::GetFlowSandeshActionParams(fe->data().match_p.action_info,
    1352         136 :                                           info->action);
    1353         136 :     info->sg_rule_uuid = fe->sg_rule_uuid();
    1354         136 :     info->nw_ace_uuid = fe->nw_ace_uuid();
    1355         136 :     info->aps_rule_uuid = fe->fw_policy_uuid();
    1356         136 :     if (FlowEntry::ShouldDrop(fe->data().match_p.action_info.action)) {
    1357          14 :         info->drop_reason = FlowEntry::DropReasonStr(fe->data().drop_reason);
    1358             :     }
    1359             : }
    1360             : 
    1361          96 : void SessionStatsCollector::CopyFlowInfo(SessionStatsInfo &session,
    1362             :                                          const RevFlowDepParams *params) {
    1363          96 :     SessionExportInfo &info = session.export_info;
    1364          96 :     FlowEntry *fe = session.fwd_flow.flow.get();
    1365          96 :     FlowEntry *rfe = session.rev_flow.flow.get();
    1366          96 :     info.valid = true;
    1367             : 
    1368          96 :     const Interface *itf = fe->intf_entry();
    1369          96 :     if ((itf !=  NULL) && (itf->type() == Interface::VM_INTERFACE)) {
    1370          96 :         const VmInterface *vmi = static_cast<const VmInterface *>(itf);
    1371          96 :         if (vmi != NULL) {
    1372          96 :             info.vmi_slo_list = vmi->slo_list();
    1373          96 :             if (vmi->vn()) {
    1374          70 :                 info.vn_slo_list = vmi->vn()->slo_list();
    1375             :             }
    1376             :         }
    1377             :     }
    1378             : 
    1379          96 :     if (fe->IsIngressFlow()) {
    1380          35 :         info.vm_cfg_name = fe->data().vm_cfg_name;
    1381          61 :     } else if (rfe) {
    1382             :         /* TODO: vm_cfg_name should be passed in RevFlowDepParams because rfe
    1383             :          * may now point to different UUID altogether */
    1384          61 :         info.vm_cfg_name = rfe->data().vm_cfg_name;
    1385             :     }
    1386          96 :     string rid = agent_uve_->agent()->router_id().to_string();
    1387          96 :     if (fe->is_flags_set(FlowEntry::LocalFlow)) {
    1388          20 :         info.other_vrouter = rid;
    1389             :     } else {
    1390          76 :         info.other_vrouter = fe->peer_vrouter();
    1391             :     }
    1392          96 :     info.underlay_proto = fe->tunnel_type().GetType();
    1393          96 :     CopyFlowInfoInternal(&info.fwd_flow, session.fwd_flow.uuid, fe);
    1394          96 :     if (params) {
    1395          56 :         FlowTable::GetFlowSandeshActionParams(params->action_info_,
    1396          56 :                                               info.rev_flow.action);
    1397          56 :         info.rev_flow.sg_rule_uuid = params->sg_uuid_;
    1398          56 :         info.rev_flow.nw_ace_uuid = params->nw_ace_uuid_;
    1399          56 :         if (FlowEntry::ShouldDrop(params->action_info_.action)) {
    1400           0 :             info.rev_flow.drop_reason = FlowEntry::DropReasonStr(params->
    1401           0 :                                                                  drop_reason_);
    1402             :         }
    1403          40 :     } else if (rfe) {
    1404          40 :         CopyFlowInfoInternal(&info.rev_flow, session.rev_flow.uuid, rfe);
    1405             :     }
    1406          96 : }
    1407             : 
    1408           0 : void SessionStatsCollector::FillSessionFlowStats
    1409             : (const SessionFlowStatsParams &stats, SessionFlowInfo *flow_info,
    1410             :  bool is_sampling, bool is_logging) const {
    1411           0 :     if (!stats.valid) {
    1412           0 :         return;
    1413             :     }
    1414           0 :     flow_info->set_tcp_flags(stats.tcp_flags);
    1415           0 :     flow_info->set_underlay_source_port(stats.underlay_src_port);
    1416           0 :     if (is_sampling) {
    1417           0 :         flow_info->set_sampled_pkts(stats.diff_packets);
    1418           0 :         flow_info->set_sampled_bytes(stats.diff_bytes);
    1419             :     }
    1420           0 :     if (is_logging) {
    1421           0 :         flow_info->set_logged_pkts(stats.diff_packets);
    1422           0 :         flow_info->set_logged_bytes(stats.diff_bytes);
    1423             :     }
    1424             : }
    1425             : 
    1426           0 : void SessionStatsCollector::FillSessionFlowInfo
    1427             : (const SessionFlowStatsInfo &session_flow, const SessionStatsInfo &sinfo,
    1428             :  const SessionFlowExportInfo &einfo, SessionFlowInfo *flow_info) const {
    1429           0 :     FlowEntry *fe = session_flow.flow.get();
    1430           0 :     std::string action_str, drop_reason = "";
    1431             : 
    1432           0 :     flow_info->set_flow_uuid(session_flow.uuid);
    1433           0 :     flow_info->set_setup_time(sinfo.setup_time);
    1434           0 :     if (sinfo.teardown_time) {
    1435           0 :         flow_info->set_teardown_time(sinfo.teardown_time);
    1436           0 :         flow_info->set_teardown_bytes(session_flow.total_bytes);
    1437           0 :         flow_info->set_teardown_pkts(session_flow.total_packets);
    1438             :     }
    1439           0 :     if (sinfo.deleted) {
    1440           0 :         if (!sinfo.export_info.valid) {
    1441           0 :             return;
    1442             :         }
    1443           0 :         if (!einfo.action.empty()) {
    1444           0 :             flow_info->set_action(einfo.action);
    1445             :         }
    1446           0 :         if (!einfo.sg_rule_uuid.empty()) {
    1447           0 :             flow_info->set_sg_rule_uuid(StringToUuid(einfo.sg_rule_uuid));
    1448             :         }
    1449           0 :         if (!einfo.nw_ace_uuid.empty()) {
    1450           0 :             flow_info->set_nw_ace_uuid(StringToUuid(einfo.nw_ace_uuid));
    1451             :         }
    1452           0 :         if (!einfo.drop_reason.empty()) {
    1453           0 :             flow_info->set_drop_reason(einfo.drop_reason);
    1454             :         }
    1455             :     } else {
    1456           0 :         FlowTable::GetFlowSandeshActionParams(fe->data().match_p.action_info,
    1457             :                                               action_str);
    1458           0 :         flow_info->set_action(action_str);
    1459           0 :         flow_info->set_sg_rule_uuid(StringToUuid(fe->sg_rule_uuid()));
    1460           0 :         flow_info->set_nw_ace_uuid(StringToUuid(fe->nw_ace_uuid()));
    1461           0 :         if (FlowEntry::ShouldDrop(fe->data().match_p.action_info.action)) {
    1462           0 :             drop_reason = FlowEntry::DropReasonStr(fe->data().drop_reason);
    1463           0 :             flow_info->set_drop_reason(drop_reason);
    1464             :         }
    1465             :     }
    1466           0 : }
    1467             : 
    1468           0 : bool SessionStatsCollector::CheckAndDeleteSessionStatsFlow(
    1469             :     SessionPreAggInfo::SessionMap::iterator session_map_iter) {
    1470           0 :     FlowEntry *fe = session_map_iter->second.fwd_flow.flow.get();
    1471           0 :     FlowEntry *rfe = session_map_iter->second.rev_flow.flow.get();
    1472           0 :     FLOW_LOCK(fe, rfe, FlowEvent::FLOW_MESSAGE);
    1473           0 :     if (fe->deleted()) {
    1474           0 :         DeleteSession(fe, session_map_iter->first.uuid,
    1475             :                           GetCurrentTime(), NULL);
    1476           0 :         return true;
    1477             :     }
    1478           0 :     return false;
    1479           0 : }
    1480             : 
    1481           0 : bool SessionStatsCollector::SessionStatsChangedLocked
    1482             :     (SessionPreAggInfo::SessionMap::iterator session_map_iter,
    1483             :      SessionStatsParams *params) const {
    1484           0 :     FlowEntry *fe = session_map_iter->second.fwd_flow.flow.get();
    1485           0 :     FlowEntry *rfe = session_map_iter->second.rev_flow.flow.get();
    1486           0 :     FLOW_LOCK(fe, rfe, FlowEvent::FLOW_MESSAGE);
    1487           0 :     return SessionStatsChangedUnlocked(session_map_iter, params);
    1488           0 : }
    1489             : 
    1490         101 : bool SessionStatsCollector::SessionStatsChangedUnlocked
    1491             :     (SessionPreAggInfo::SessionMap::iterator session_map_iter,
    1492             :      SessionStatsParams *params) const {
    1493             : 
    1494         101 :     bool fwd_updated = FetchFlowStats(&session_map_iter->second.fwd_flow,
    1495             :                                       &params->fwd_flow);
    1496         101 :     bool rev_updated = FetchFlowStats(&session_map_iter->second.rev_flow,
    1497             :                                       &params->rev_flow);
    1498         101 :     return (fwd_updated || rev_updated);
    1499             : }
    1500             : 
    1501         202 : bool SessionStatsCollector::FetchFlowStats
    1502             : (SessionFlowStatsInfo *info, SessionFlowStatsParams *params) const {
    1503             :     vr_flow_stats k_stats;
    1504             :     KFlowData kinfo;
    1505             :     uint64_t k_bytes, bytes, k_packets;
    1506         202 :     const vr_flow_entry *k_flow = NULL;
    1507         202 :     KSyncFlowMemory *ksync_obj = agent_uve_->agent()->ksync()->
    1508         202 :         ksync_flow_memory();
    1509             :     /* Update gen-id and flow-handle before reading stats using them. For
    1510             :      * reverse-flow, it is possible that flow-handle is not set yet
    1511             :      */
    1512         202 :     FlowEntry *fe = info->flow.get();
    1513         202 :     if (fe && (info->uuid == fe->uuid())) {
    1514         192 :         info->flow_handle = fe->flow_handle();
    1515         192 :         info->gen_id = fe->gen_id();
    1516             :     }
    1517             : 
    1518         202 :     k_flow = ksync_obj->GetKFlowStatsAndInfo(info->flow->key(),
    1519             :                                              info->flow_handle,
    1520         202 :                                              info->gen_id, &k_stats, &kinfo);
    1521         202 :     if (!k_flow) {
    1522          99 :         SandeshFlowKey skey;
    1523          99 :         skey.set_nh(info->flow->key().nh);
    1524          99 :         skey.set_sip(info->flow->key().src_addr.to_string());
    1525          99 :         skey.set_dip(info->flow->key().dst_addr.to_string());
    1526          99 :         skey.set_src_port(info->flow->key().src_port);
    1527          99 :         skey.set_dst_port(info->flow->key().dst_port);
    1528          99 :         skey.set_protocol(info->flow->key().protocol);
    1529          99 :         SESSION_STATS_TRACE(Err, "Fetching stats failed", info->flow_handle,
    1530             :                             info->gen_id, skey);
    1531          99 :         return false;
    1532          99 :     }
    1533             : 
    1534           0 :     k_bytes = FlowStatsCollector::GetFlowStats(k_stats.flow_bytes_oflow,
    1535         103 :                                                k_stats.flow_bytes);
    1536           0 :     k_packets = FlowStatsCollector::GetFlowStats(k_stats.flow_packets_oflow,
    1537         103 :                                                  k_stats.flow_packets);
    1538             : 
    1539         103 :     bytes = 0x0000ffffffffffffULL & info->total_bytes;
    1540             : 
    1541         103 :     if (bytes != k_bytes) {
    1542         103 :         uint64_t total_bytes = GetUpdatedSessionFlowBytes(info->total_bytes,
    1543             :                                                           k_bytes);
    1544             :         uint64_t total_packets = GetUpdatedSessionFlowPackets
    1545         103 :             (info->total_packets, k_packets);
    1546         103 :         params->diff_bytes = total_bytes - info->total_bytes;
    1547         103 :         params->diff_packets = total_packets - info->total_packets;
    1548         103 :         info->total_bytes = total_bytes;
    1549         103 :         info->total_packets = total_packets;
    1550         103 :         params->tcp_flags = kinfo.tcp_flags;
    1551         103 :         params->underlay_src_port = kinfo.underlay_src_port;
    1552         103 :         params->valid = true;
    1553         103 :         return true;
    1554             :     }
    1555           0 :     return false;
    1556             : }
    1557             : 
    1558           0 : void SessionStatsCollector::FillSessionInfoLocked
    1559             :     (SessionPreAggInfo::SessionMap::iterator session_map_iter,
    1560             :      const SessionStatsParams &stats, SessionInfo *session_info,
    1561             :      SessionIpPort *session_key, bool is_sampling, bool is_logging) const {
    1562           0 :     FlowEntry *fe = session_map_iter->second.fwd_flow.flow.get();
    1563           0 :     FlowEntry *rfe = session_map_iter->second.rev_flow.flow.get();
    1564           0 :     FLOW_LOCK(fe, rfe, FlowEvent::FLOW_MESSAGE);
    1565           0 :     FillSessionInfoUnlocked(session_map_iter, stats, session_info, session_key, NULL,
    1566             :                             true, is_sampling, is_logging);
    1567           0 : }
    1568             : 
    1569           0 : void SessionStatsCollector::FillSessionEvictStats
    1570             :     (SessionPreAggInfo::SessionMap::iterator session_map_iter,
    1571             :      SessionInfo *session_info, bool is_sampling, bool is_logging) const {
    1572           0 :     const SessionStatsParams &estats = session_map_iter->second.evict_stats;
    1573           0 :     if (!estats.fwd_flow.valid) {
    1574           0 :         return;
    1575             :     }
    1576           0 :     if (is_logging) {
    1577           0 :         session_info->forward_flow_info.set_logged_pkts(estats.fwd_flow.
    1578           0 :                                                         diff_packets);
    1579           0 :         session_info->forward_flow_info.set_logged_bytes(estats.fwd_flow.
    1580           0 :                                                          diff_bytes);
    1581             :         /* TODO: Evict stats for reverse flow is not supported yet */
    1582           0 :         session_info->reverse_flow_info.set_logged_pkts(0);
    1583           0 :         session_info->reverse_flow_info.set_logged_bytes(0);
    1584             :     }
    1585           0 :     if (is_sampling) {
    1586           0 :         session_info->forward_flow_info.set_sampled_pkts(estats.fwd_flow.
    1587           0 :                                                          diff_packets);
    1588           0 :         session_info->forward_flow_info.set_sampled_bytes(estats.fwd_flow.
    1589           0 :                                                           diff_bytes);
    1590             :         /* TODO: Evict stats for reverse flow is not supported yet */
    1591           0 :         session_info->reverse_flow_info.set_sampled_pkts(0);
    1592           0 :         session_info->reverse_flow_info.set_sampled_bytes(0);
    1593             :     }
    1594             : }
    1595             : 
    1596           0 : void SessionStatsCollector::FillSessionInfoUnlocked
    1597             :     (SessionPreAggInfo::SessionMap::iterator session_map_iter,
    1598             :      const SessionStatsParams &stats,
    1599             :      SessionInfo *session_info,
    1600             :      SessionIpPort *session_key,
    1601             :      const RevFlowDepParams *params,
    1602             :      bool read_flow, bool is_sampling, bool is_logging) const {
    1603           0 :     string rid = agent_uve_->agent()->router_id().to_string();
    1604           0 :     FlowEntry *fe = session_map_iter->second.fwd_flow.flow.get();
    1605           0 :     FlowEntry *rfe = session_map_iter->second.rev_flow.flow.get();
    1606           0 :     boost::system::error_code ec;
    1607             :     /*
    1608             :      * Fill the session Key
    1609             :      */
    1610           0 :     session_key->set_ip(session_map_iter->first.remote_ip);
    1611           0 :     session_key->set_port(session_map_iter->first.client_port);
    1612           0 :     FillSessionFlowInfo(session_map_iter->second.fwd_flow,
    1613           0 :                         session_map_iter->second,
    1614           0 :                         session_map_iter->second.export_info.fwd_flow,
    1615             :                         &session_info->forward_flow_info);
    1616           0 :     FillSessionFlowInfo(session_map_iter->second.rev_flow,
    1617           0 :                         session_map_iter->second,
    1618           0 :                         session_map_iter->second.export_info.rev_flow,
    1619             :                         &session_info->reverse_flow_info);
    1620           0 :     bool first_time_export = false;
    1621           0 :     if (!session_map_iter->second.exported_atleast_once) {
    1622           0 :         first_time_export = true;
    1623             :         /* Mark the flow as exported */
    1624           0 :         session_map_iter->second.exported_atleast_once = true;
    1625             :     }
    1626             : 
    1627           0 :     const bool &evicted = session_map_iter->second.evicted;
    1628           0 :     const bool &deleted = session_map_iter->second.deleted;
    1629           0 :     if (evicted) {
    1630           0 :         const SessionStatsParams &estats = session_map_iter->second.evict_stats;
    1631           0 :         FillSessionEvictStats(session_map_iter, session_info, is_sampling,
    1632             :                               is_logging);
    1633           0 :         flow_stats_manager_->UpdateSessionExportStats(1, first_time_export,
    1634           0 :                                                       estats.sampled);
    1635             :     } else {
    1636           0 :         const SessionStatsParams *real_stats = &stats;
    1637           0 :         if (deleted) {
    1638           0 :             real_stats = &session_map_iter->second.del_stats;
    1639             :         }
    1640           0 :         FillSessionFlowStats(real_stats->fwd_flow,
    1641             :                              &session_info->forward_flow_info, is_sampling,
    1642             :                              is_logging);
    1643           0 :         FillSessionFlowStats(real_stats->rev_flow,
    1644             :                              &session_info->reverse_flow_info, is_sampling,
    1645             :                              is_logging);
    1646           0 :         flow_stats_manager_->UpdateSessionExportStats(1, first_time_export,
    1647           0 :                                                       real_stats->sampled);
    1648             :     }
    1649           0 :     if (deleted) {
    1650           0 :         SessionExportInfo &info = session_map_iter->second.export_info;
    1651           0 :         if (info.valid) {
    1652           0 :             if (!info.vm_cfg_name.empty()) {
    1653           0 :                 session_info->set_vm(info.vm_cfg_name);
    1654             :             }
    1655           0 :             session_info->set_other_vrouter_ip(
    1656           0 :                 AddressFromString(info.other_vrouter, &ec));
    1657           0 :             session_info->set_underlay_proto(info.underlay_proto);
    1658             :         }
    1659             :     } else {
    1660           0 :         session_info->set_vm(fe->data().vm_cfg_name);
    1661           0 :         if (fe->is_flags_set(FlowEntry::LocalFlow)) {
    1662           0 :             session_info->set_other_vrouter_ip(AddressFromString(rid, &ec));
    1663             :         } else {
    1664             :             /* For Egress flows, pick VM name from reverse flow */
    1665           0 :             if (!fe->IsIngressFlow() && rfe) {
    1666           0 :                 session_info->set_vm(rfe->data().vm_cfg_name);
    1667             :             }
    1668           0 :             session_info->set_other_vrouter_ip(
    1669           0 :                  AddressFromString(fe->peer_vrouter(), &ec));
    1670             :         }
    1671           0 :         session_info->set_underlay_proto(fe->tunnel_type().GetType());
    1672             :     }
    1673           0 : }
    1674             : 
    1675           0 : void SessionStatsCollector::UpdateAggregateStats(const SessionInfo &sinfo,
    1676             :                                                  SessionAggInfo *agg_info,
    1677             :                                                  bool is_sampling,
    1678             :                                                  bool is_logging) const {
    1679           0 :     if (is_sampling) {
    1680           0 :         agg_info->set_sampled_forward_bytes(agg_info->get_sampled_forward_bytes() +
    1681           0 :             sinfo.get_forward_flow_info().get_sampled_bytes());
    1682           0 :         agg_info->set_sampled_forward_pkts(agg_info->get_sampled_forward_pkts() +
    1683           0 :             sinfo.get_forward_flow_info().get_sampled_pkts());
    1684           0 :         agg_info->set_sampled_reverse_bytes(agg_info->get_sampled_reverse_bytes() +
    1685           0 :             sinfo.get_reverse_flow_info().get_sampled_bytes());
    1686           0 :         agg_info->set_sampled_reverse_pkts(agg_info->get_sampled_reverse_pkts() +
    1687           0 :             sinfo.get_reverse_flow_info().get_sampled_pkts());
    1688             :     }
    1689           0 :     if (is_logging) {
    1690           0 :         agg_info->set_logged_forward_bytes(agg_info->get_logged_forward_bytes() +
    1691           0 :             sinfo.get_forward_flow_info().get_logged_bytes());
    1692           0 :         agg_info->set_logged_forward_pkts(agg_info->get_logged_forward_pkts() +
    1693           0 :             sinfo.get_forward_flow_info().get_logged_pkts());
    1694           0 :         agg_info->set_logged_reverse_bytes(agg_info->get_logged_reverse_bytes() +
    1695           0 :             sinfo.get_reverse_flow_info().get_logged_bytes());
    1696           0 :         agg_info->set_logged_reverse_pkts(agg_info->get_logged_reverse_pkts() +
    1697           0 :             sinfo.get_reverse_flow_info().get_logged_pkts());
    1698             :     }
    1699           0 : }
    1700             : 
    1701           0 : void SessionStatsCollector::FillSessionAggInfo
    1702             : (SessionEndpointInfo::SessionAggMap::iterator it, SessionIpPortProtocol *key)
    1703             :  const {
    1704             :     /*
    1705             :      * Fill the session agg key
    1706             :      */
    1707           0 :     key->set_local_ip(it->first.local_ip);
    1708           0 :     key->set_service_port(it->first.server_port);
    1709           0 :     key->set_protocol(it->first.proto);
    1710           0 : }
    1711             : 
    1712           0 : void SessionStatsCollector::FillSessionTags(const TagList &list,
    1713             :                                             SessionEndpoint *ep) const {
    1714           0 :     UveTagData tinfo(UveTagData::SET);
    1715           0 :     agent_uve_->BuildTagNamesFromList(list, &tinfo);
    1716           0 :     if (!tinfo.application.empty()) {
    1717           0 :         ep->set_application(tinfo.application);
    1718             :     }
    1719           0 :     if (!tinfo.tier.empty()) {
    1720           0 :         ep->set_tier(tinfo.tier);
    1721             :     }
    1722           0 :     if (!tinfo.site.empty()) {
    1723           0 :         ep->set_site(tinfo.site);
    1724             :     }
    1725           0 :     if (!tinfo.deployment.empty()) {
    1726           0 :         ep->set_deployment(tinfo.deployment);
    1727             :     }
    1728           0 :     if (tinfo.label_set.size() != 0) {
    1729           0 :         ep->set_labels(tinfo.label_set);
    1730             :     }
    1731           0 :     if (tinfo.custom_tag_set.size() != 0) {
    1732           0 :         ep->set_custom_tags(tinfo.custom_tag_set);
    1733             :     }
    1734           0 : }
    1735             : 
    1736           0 : void SessionStatsCollector::FillSessionRemoteTags(const TagList &list,
    1737             :                                                   SessionEndpoint *ep) const {
    1738           0 :     UveTagData tinfo(UveTagData::SET);
    1739           0 :     agent_uve_->BuildTagIdsFromList(list, &tinfo);
    1740           0 :     if (!tinfo.application.empty()){
    1741           0 :         ep->set_remote_application(tinfo.application);
    1742             :     }
    1743           0 :     if (!tinfo.tier.empty()){
    1744           0 :         ep->set_remote_tier(tinfo.tier);
    1745             :     }
    1746           0 :     if (!tinfo.site.empty()){
    1747           0 :         ep->set_remote_site(tinfo.site);
    1748             :     }
    1749           0 :     if (!tinfo.deployment.empty()){
    1750           0 :         ep->set_remote_deployment(tinfo.deployment);
    1751             :     }
    1752           0 :     if (tinfo.label_set.size() != 0) {
    1753           0 :         ep->set_remote_labels(tinfo.label_set);
    1754             :     }
    1755           0 :     if (tinfo.custom_tag_set.size() != 0) {
    1756           0 :         ep->set_remote_custom_tags(tinfo.custom_tag_set);
    1757             :     }
    1758           0 : }
    1759             : 
    1760           0 : void SessionStatsCollector::FillSessionEndpoint(SessionEndpointMap::iterator it,
    1761             :                                                 SessionEndpoint *session_ep)
    1762             :                                                 const {
    1763           0 :     string rid = agent_uve_->agent()->router_id().to_string();
    1764           0 :     boost::system::error_code ec;
    1765             : 
    1766           0 :     session_ep->set_vmi(it->first.vmi_cfg_name);
    1767           0 :     session_ep->set_vn(it->first.local_vn);
    1768           0 :     session_ep->set_remote_vn(it->first.remote_vn);
    1769           0 :     session_ep->set_is_client_session(it->first.is_client_session);
    1770           0 :     session_ep->set_is_si(it->first.is_si);
    1771           0 :     if (!it->first.remote_prefix.empty()) {
    1772           0 :         session_ep->set_remote_prefix(it->first.remote_prefix);
    1773             :     }
    1774           0 :     session_ep->set_security_policy_rule(it->first.match_policy);
    1775           0 :     if (it->first.local_tagset.size() > 0) {
    1776           0 :         FillSessionTags(it->first.local_tagset, session_ep);
    1777             :     }
    1778           0 :     if (it->first.remote_tagset.size() > 0) {
    1779           0 :         FillSessionRemoteTags(it->first.remote_tagset, session_ep);
    1780             :     }
    1781           0 :     session_ep->set_vrouter_ip(AddressFromString(rid, &ec));
    1782           0 : }
    1783             : 
    1784          26 : bool SessionStatsCollector::ProcessSessionEndpoint
    1785             :     (const SessionEndpointMap::iterator &it) {
    1786          26 :     SessionEndpointInfo::SessionAggMap::iterator session_agg_map_iter;
    1787          26 :     SessionEndpointInfo::SessionAggMap::iterator prev_agg_iter;
    1788          26 :     SessionPreAggInfo::SessionMap::iterator session_map_iter, prev;
    1789             : 
    1790          26 :     SessionInfo session_info;
    1791          26 :     SessionIpPort session_key;
    1792          26 :     uint32_t session_count = 0, session_agg_count = 0;
    1793          26 :     bool exit = false, ep_completed = true;
    1794             : 
    1795          26 :     SessionEndpoint &session_ep = session_msg_list_[GetSessionMsgIdx()];
    1796             : 
    1797          26 :     session_agg_map_iter = it->second.session_agg_map_.
    1798          26 :         lower_bound(session_agg_iteration_key_);
    1799          75 :     while (session_agg_map_iter != it->second.session_agg_map_.end()) {
    1800          52 :         SessionAggInfo session_agg_info;
    1801          52 :         SessionIpPortProtocol session_agg_key;
    1802          52 :         session_count = 0;
    1803          52 :         session_map_iter = session_agg_map_iter->second.session_map_.
    1804          52 :             lower_bound(session_iteration_key_);
    1805         109 :         while (session_map_iter != session_agg_map_iter->second.session_map_.end()) {
    1806          57 :             prev = session_map_iter;
    1807          57 :             SessionStatsParams params;
    1808          57 :             if (!session_map_iter->second.deleted &&
    1809           0 :                 !session_map_iter->second.evicted) {
    1810           0 :                 bool delete_marked = CheckAndDeleteSessionStatsFlow(session_map_iter);
    1811           0 :                 if (!delete_marked) {
    1812           0 :                     bool changed = SessionStatsChangedLocked(session_map_iter,
    1813             :                                                     &params);
    1814           0 :                     if (!changed && session_map_iter->second.exported_atleast_once) {
    1815           0 :                         ++session_map_iter;
    1816          57 :                         continue;
    1817             :                     }
    1818             :                 }
    1819             :             }
    1820             : 
    1821          57 :             bool is_sampling = true;
    1822          57 :             if (IsSamplingEnabled()) {
    1823          57 :                 is_sampling = SampleSession(session_map_iter, &params);
    1824             :             }
    1825          57 :             bool is_logging = CheckSessionLogging(session_map_iter->second);
    1826             : 
    1827             :             /* Ignore session export if sampling & logging drop the session */
    1828          57 :             if (!is_sampling && !is_logging) {
    1829          57 :                 ++session_map_iter;
    1830          57 :                 if (prev->second.deleted) {
    1831          57 :                     session_agg_map_iter->second.session_map_.erase(prev);
    1832             :                 }
    1833          57 :                 continue;
    1834             :             }
    1835           0 :             if (session_map_iter->second.deleted) {
    1836           0 :                 FillSessionInfoUnlocked(session_map_iter, params, &session_info,
    1837             :                                         &session_key, NULL, true, is_sampling,
    1838             :                                         is_logging);
    1839             :             } else {
    1840           0 :                 FillSessionInfoLocked(session_map_iter, params, &session_info,
    1841             :                                       &session_key, is_sampling, is_logging);
    1842             :             }
    1843           0 :             session_agg_info.sessionMap.insert(make_pair(session_key,
    1844             :                                                          session_info));
    1845           0 :             UpdateAggregateStats(session_info, &session_agg_info, is_sampling,
    1846             :                                  is_logging);
    1847           0 :             ++session_map_iter;
    1848           0 :             ++session_count;
    1849           0 :             if (prev->second.deleted) {
    1850           0 :                 session_agg_map_iter->second.session_map_.erase(prev);
    1851             :             }
    1852           0 :             if (session_count ==
    1853           0 :                 agent_uve_->agent()->params()->max_sessions_per_aggregate()) {
    1854           0 :                 exit = true;
    1855           0 :                 break;
    1856             :             }
    1857             :         }
    1858          52 :         if (session_count) {
    1859           0 :             FillSessionAggInfo(session_agg_map_iter, &session_agg_key);
    1860           0 :             session_ep.sess_agg_info.insert(make_pair(session_agg_key,
    1861             :                                                       session_agg_info));
    1862             :         }
    1863          52 :         if (exit) {
    1864           0 :             break;
    1865             :         }
    1866          52 :         session_iteration_key_.Reset();
    1867          52 :         prev_agg_iter = session_agg_map_iter;
    1868          52 :         session_agg_map_iter++;
    1869          52 :         if (prev_agg_iter->second.session_map_.size() == 0) {
    1870          52 :             it->second.session_agg_map_.erase(prev_agg_iter);
    1871             :         }
    1872          52 :         ++session_agg_count;
    1873          52 :         if (session_agg_count ==
    1874          52 :             agent_uve_->agent()->params()->max_aggregates_per_session_endpoint()) {
    1875           3 :             break;
    1876             :         }
    1877          55 :     }
    1878             :     /* Don't export SessionEndpoint if there are 0 aggregates */
    1879          26 :     if (session_ep.sess_agg_info.size()) {
    1880           0 :         FillSessionEndpoint(it, &session_ep);
    1881           0 :         EnqueueSessionMsg();
    1882             :     }
    1883             : 
    1884          26 :     if (session_count ==
    1885          26 :         agent_uve_->agent()->params()->max_sessions_per_aggregate()) {
    1886           0 :         ep_completed = false;
    1887           0 :         session_ep_iteration_key_ = it->first;
    1888           0 :         session_agg_iteration_key_ = session_agg_map_iter->first;
    1889           0 :         if (session_map_iter == session_agg_map_iter->second.session_map_.end()) {
    1890           0 :             prev_agg_iter = session_agg_map_iter;
    1891           0 :             ++session_agg_map_iter;
    1892           0 :             if (prev_agg_iter->second.session_map_.size() == 0) {
    1893           0 :                 it->second.session_agg_map_.erase(prev_agg_iter);
    1894             :             }
    1895           0 :             if (session_agg_map_iter == it->second.session_agg_map_.end()) {
    1896             :                 /* session_iteration_key_ and session_agg_iteration_key_ are
    1897             :                  * both reset when ep_completed is returned as true in the
    1898             :                  * calling function */
    1899           0 :                 ep_completed = true;
    1900             :             } else {
    1901           0 :                 session_iteration_key_.Reset();
    1902           0 :                 session_agg_iteration_key_ = session_agg_map_iter->first;
    1903             :             }
    1904             :         } else {
    1905           0 :             session_iteration_key_ = session_map_iter->first;
    1906             :         }
    1907          26 :     } else if (session_agg_count ==
    1908          26 :                agent_uve_->agent()->params()->
    1909          26 :                max_aggregates_per_session_endpoint()) {
    1910           3 :         ep_completed = false;
    1911           3 :         session_ep_iteration_key_ = it->first;
    1912           3 :         if (session_agg_map_iter == it->second.session_agg_map_.end()) {
    1913             :             /* session_iteration_key_ and session_agg_iteration_key_ are both
    1914             :              * reset when ep_completed is returned as true in the calling
    1915             :              * function */
    1916           0 :             ep_completed = true;
    1917             :         } else {
    1918           3 :             session_agg_iteration_key_ = session_agg_map_iter->first;
    1919           3 :             session_iteration_key_.Reset();
    1920             :         }
    1921             :     }
    1922          26 :     return ep_completed;
    1923          26 : }
    1924             : 
    1925           6 : uint32_t SessionStatsCollector::RunSessionEndpointStats(uint32_t max_count) {
    1926             :     SessionEndpointMap::iterator it = session_endpoint_map_.
    1927           6 :         lower_bound(session_ep_iteration_key_);
    1928           6 :     if (it == session_endpoint_map_.end()) {
    1929           0 :         it = session_endpoint_map_.begin();
    1930             :     }
    1931           6 :     if (it == session_endpoint_map_.end()) {
    1932           0 :         return 0;
    1933             :     }
    1934             : 
    1935           6 :     uint32_t count = 0;
    1936          32 :     while (count < max_count) {
    1937          32 :         if (it == session_endpoint_map_.end()) {
    1938           6 :             break;
    1939             :         }
    1940             : 
    1941             :         /* ProcessSessionEndpoint will build 1 SessionEndpoint message. This
    1942             :          * may or may not include all aggregates and all sessions within each
    1943             :          * aggregate. It returns true if the built message includes all
    1944             :          * aggregates and all sessions of each aggregate */
    1945          26 :         bool ep_completed = ProcessSessionEndpoint(it);
    1946          26 :         ++count;
    1947          26 :         if (ep_completed) {
    1948          23 :             SessionEndpointMap::iterator prev = it;
    1949          23 :             ++it;
    1950          23 :             ++session_ep_visited_;
    1951          23 :             session_agg_iteration_key_.Reset();
    1952          23 :             session_iteration_key_.Reset();
    1953          23 :             if (prev->second.session_agg_map_.size() == 0) {
    1954          23 :                 session_endpoint_map_.erase(prev);
    1955             :             }
    1956             :         }
    1957             :     }
    1958             : 
    1959             :     //Send any pending session export messages
    1960           6 :     DispatchPendingSessionMsg();
    1961             : 
    1962             :     // Update iterator for next pass
    1963           6 :     if (it == session_endpoint_map_.end()) {
    1964           6 :         session_ep_iteration_key_.Reset();
    1965             :     } else {
    1966           0 :         session_ep_iteration_key_ = it->first;
    1967             :     }
    1968             : 
    1969           6 :     session_task_ = NULL;
    1970           6 :     return count;
    1971             : }
    1972             : /////////////////////////////////////////////////////////////////////////////
    1973             : // Introspect routines
    1974             : /////////////////////////////////////////////////////////////////////////////
    1975             : //TBD
    1976             : 
    1977             : /////////////////////////////////////////////////////////////////////////////
    1978             : // Session Stats task
    1979             : /////////////////////////////////////////////////////////////////////////////
    1980           6 : SessionStatsCollector::SessionTask::SessionTask(SessionStatsCollector *ssc) :
    1981           6 :     Task(ssc->task_id(), ssc->instance_id()), ssc_(ssc) {
    1982           6 : }
    1983             : 
    1984          12 : SessionStatsCollector::SessionTask::~SessionTask() {
    1985          12 : }
    1986             : 
    1987           0 : std::string SessionStatsCollector::SessionTask::Description() const {
    1988           0 :     return "Session Stats Collector Task";
    1989             : }
    1990             : 
    1991           6 : bool SessionStatsCollector::SessionTask::Run() {
    1992           6 :     ssc_->RunSessionEndpointStats(kSessionsPerTask);
    1993           6 :     return true;
    1994             : }
    1995             : 
    1996          57 : bool SessionStatsCollector::IsSamplingEnabled() const {
    1997          57 :     int32_t cfg_rate = agent_uve_->agent()->oper_db()->global_vrouter()->
    1998          57 :                         flow_export_rate();
    1999          57 :     if (cfg_rate == GlobalVrouter::kDisableSampling) {
    2000           0 :         return false;
    2001             :     }
    2002          57 :     return true;
    2003             : }
    2004             : 
    2005          57 : bool SessionStatsCollector::SampleSession
    2006             :     (SessionPreAggInfo::SessionMap::iterator session_map_iter,
    2007             :      SessionStatsParams *params) const {
    2008          57 :     int32_t cfg_rate = agent_uve_->agent()->oper_db()->global_vrouter()->
    2009          57 :                         flow_export_rate();
    2010             :     /* If session export is disabled, update stats and return */
    2011          57 :     if (!cfg_rate) {
    2012          57 :         flow_stats_manager_->session_export_disable_drops_++;
    2013          57 :         return false;
    2014             :     }
    2015           0 :     const bool &deleted = session_map_iter->second.deleted;
    2016           0 :     const bool &evicted = session_map_iter->second.evicted;
    2017           0 :     SessionStatsParams *stats = params;
    2018           0 :     if (evicted) {
    2019           0 :         stats = &session_map_iter->second.evict_stats;
    2020           0 :     } else if (deleted) {
    2021           0 :         stats = &session_map_iter->second.del_stats;
    2022             :     }
    2023           0 :     stats->sampled = false;
    2024             :     /* For session-sampling diff_bytes should consider the diff bytes for both
    2025             :      * forward and reverse flow */
    2026           0 :     uint64_t diff_bytes = stats->fwd_flow.diff_bytes +
    2027           0 :                           stats->rev_flow.diff_bytes;
    2028           0 :     const SessionStatsInfo &info = session_map_iter->second;
    2029             :     /* Subject a flow to sampling algorithm only when all of below is met:-
    2030             :      * a. actual session-export-rate is >= 80% of configured flow-export-rate.
    2031             :      *    This is done only for first time.
    2032             :      * b. diff_bytes is lesser than the threshold
    2033             :      * c. Flow-sample does not have teardown time or the sample for the flow is
    2034             :      *    not exported earlier.
    2035             :      */
    2036           0 :     bool subject_flows_to_algorithm = false;
    2037           0 :     if ((diff_bytes < threshold()) &&
    2038           0 :         (!info.teardown_time || !info.exported_atleast_once) &&
    2039           0 :         ((!flow_stats_manager_->sessions_sampled_atleast_once_ &&
    2040           0 :          flow_stats_manager_->session_export_rate() >= ((double)cfg_rate) * 0.8)
    2041           0 :          || flow_stats_manager_->sessions_sampled_atleast_once_)) {
    2042           0 :         subject_flows_to_algorithm = true;
    2043           0 :         flow_stats_manager_->set_sessions_sampled_atleast_once();
    2044             :     }
    2045             : 
    2046           0 :     if (subject_flows_to_algorithm) {
    2047           0 :         double probability = diff_bytes/threshold();
    2048           0 :         uint32_t num = rand() % threshold();
    2049           0 :         if (num > diff_bytes) {
    2050             :             /* Do not export the flow, if the random number generated is more
    2051             :              * than the diff_bytes */
    2052           0 :             flow_stats_manager_->session_export_sampling_drops_++;
    2053             :             /* The second part of the if condition below is not required but
    2054             :              * added for better readability. It is not required because
    2055             :              * exported_atleast_once() will always be false if teardown time is
    2056             :              * set. If both teardown_time and exported_atleast_once are true we
    2057             :              * will never be here */
    2058           0 :             if (info.teardown_time && !info.exported_atleast_once) {
    2059             :                 /* This counter indicates the number of sessions that were
    2060             :                  * never exported */
    2061           0 :                 flow_stats_manager_->session_export_drops_++;
    2062             :             }
    2063           0 :             return false;
    2064             :         }
    2065           0 :         stats->sampled = true;
    2066             :         /* Normalize the diff_bytes and diff_packets reported using the
    2067             :          * probability value */
    2068           0 :         if (probability == 0) {
    2069           0 :             stats->fwd_flow.diff_bytes = 0;
    2070           0 :             stats->fwd_flow.diff_packets = 0;
    2071           0 :             stats->rev_flow.diff_bytes = 0;
    2072           0 :             stats->rev_flow.diff_packets = 0;
    2073             :         } else {
    2074           0 :             stats->fwd_flow.diff_bytes = stats->fwd_flow.diff_bytes/
    2075             :                                                 probability;
    2076           0 :             stats->fwd_flow.diff_packets = stats->fwd_flow.diff_packets/
    2077             :                                                   probability;
    2078           0 :             stats->rev_flow.diff_bytes = stats->rev_flow.diff_bytes/
    2079             :                                                 probability;
    2080           0 :             stats->rev_flow.diff_packets = stats->rev_flow.diff_packets/
    2081             :                                                   probability;
    2082             :         }
    2083             :     }
    2084             : 
    2085           0 :     return true;
    2086             : }
    2087             : 
    2088           0 : uint64_t SessionStatsCollector::threshold() const {
    2089           0 :     return flow_stats_manager_->threshold();
    2090             : }
    2091             : 
    2092             : /////////////////////////////////////////////////////////////////////////////
    2093             : // SessionStatsCollectorObject methods
    2094             : /////////////////////////////////////////////////////////////////////////////
    2095           2 : SessionStatsCollectorObject::SessionStatsCollectorObject(Agent *agent,
    2096           0 :                                                    FlowStatsManager *mgr) {
    2097           4 :     for (int i = 0; i < kMaxSessionCollectors; i++) {
    2098           2 :         uint32_t instance_id = mgr->AllocateIndex();
    2099             :         boost::asio::io_context& io_ref =
    2100             :             const_cast<boost::asio::io_context&>
    2101           2 :             (*agent->event_manager()->io_service());
    2102           2 :         collectors[i].reset(
    2103             :             AgentStaticObjectFactory::CreateRef<SessionStatsCollector>(
    2104             :                 io_ref,
    2105             :                 agent->uve(), instance_id, mgr, this));
    2106             :     }
    2107           2 : }
    2108             : 
    2109           0 : SessionStatsCollector* SessionStatsCollectorObject::GetCollector(uint8_t idx) const {
    2110           0 :     if (idx >= 0 && idx < kMaxSessionCollectors) {
    2111           0 :         return collectors[idx].get();
    2112             :     }
    2113           0 :     return NULL;
    2114             : }
    2115             : 
    2116           0 : void SessionStatsCollectorObject::SetExpiryTime(int time) {
    2117           0 :     for (int i = 0; i < kMaxSessionCollectors; i++) {
    2118           0 :         collectors[i]->set_expiry_time(time);
    2119             :     }
    2120           0 : }
    2121             : 
    2122           0 : int SessionStatsCollectorObject::GetExpiryTime() const {
    2123             :     /* Same expiry time would be configured for all the collectors. Pick value
    2124             :      * from any one of them */
    2125           0 :     return collectors[0]->expiry_time();
    2126             : }
    2127             : 
    2128         374 : SessionStatsCollector* SessionStatsCollectorObject::FlowToCollector
    2129             :     (const FlowEntry *flow) {
    2130         374 :     uint8_t idx = 0;
    2131         374 :     FlowTable *table = flow->flow_table();
    2132         374 :     if (table) {
    2133         374 :         idx = table->table_index() % kMaxSessionCollectors;
    2134             :     }
    2135         374 :     return collectors[idx].get();
    2136             : }
    2137             : 
    2138           2 : void SessionStatsCollectorObject::Shutdown() {
    2139           4 :     for (int i = 0; i < kMaxSessionCollectors; i++) {
    2140           2 :         collectors[i]->Shutdown();
    2141           2 :         collectors[i].reset();
    2142             :     }
    2143           2 : }
    2144             : 
    2145           0 : size_t SessionStatsCollectorObject::Size() const {
    2146           0 :     size_t size = 0;
    2147           0 :     for (int i = 0; i < kMaxSessionCollectors; i++) {
    2148           0 :         size += collectors[i]->Size();
    2149             :     }
    2150           0 :     return size;
    2151             : }
    2152             : 
    2153           2 : void SessionStatsCollectorObject::RegisterDBClients() {
    2154           4 :     for (int i = 0; i < kMaxSessionCollectors; i++) {
    2155           2 :         if (collectors[i].get()) {
    2156           2 :             collectors[i].get()->RegisterDBClients();
    2157             :         }
    2158             :     }
    2159           2 : }
    2160             : 
    2161         374 : FlowEntry* SessionStatsReq::reverse_flow() const {
    2162         374 :     FlowEntry *rflow = NULL;
    2163         374 :     if (flow_.get()) {
    2164         374 :         rflow = flow_->reverse_flow_entry();
    2165             :     }
    2166         374 :     return rflow;
    2167             : }
    2168             : 
    2169         119 : bool FlowToSessionMap::IsEqual(FlowToSessionMap &rhs) {
    2170         119 :     if (!(session_key_.IsEqual(rhs.session_key()))) {
    2171           3 :         return false;
    2172             :     }
    2173         116 :     if (!(session_agg_key_.IsEqual(rhs.session_agg_key()))) {
    2174           0 :         return false;
    2175             :     }
    2176         116 :     if (!(session_endpoint_key_.IsEqual(rhs.session_endpoint_key()))) {
    2177          21 :         return false;
    2178             :     }
    2179          95 :     return true;
    2180             : }
    2181             : 
    2182           0 : void SessionSloState::DeleteSessionSloStateRuleEntry(std::string uuid) {
    2183           0 :     SessionSloRuleStateMap::iterator  it;
    2184           0 :     it = session_rule_state_map_.find(uuid);
    2185           0 :     if (it != session_rule_state_map_.end()) {
    2186           0 :         session_rule_state_map_.erase(it);
    2187             :     }
    2188           0 : }
    2189             : 
    2190           0 : void SessionSloState::UpdateSessionSloStateRuleEntry(std::string uuid,
    2191             :                                                      int rate) {
    2192           0 :     SessionSloRuleStateMap::iterator  it;
    2193           0 :     it = session_rule_state_map_.find(uuid);
    2194           0 :     if (it == session_rule_state_map_.end()) {
    2195           0 :         SessionSloRuleState slo_state_rule_entry = {};
    2196           0 :         slo_state_rule_entry.rate = rate;
    2197           0 :         session_rule_state_map_.insert(make_pair(uuid, slo_state_rule_entry));
    2198             :     } else {
    2199           0 :         SessionSloRuleState &prev = it->second;
    2200           0 :         if (prev.rate != rate) {
    2201           0 :             prev.rate = rate;
    2202           0 :             prev.ref_count = 0;
    2203             :         }
    2204             :     }
    2205             : 
    2206           0 : }
    2207             : 
    2208           0 : bool SessionSloState::UpdateSessionSloStateRuleRefCount(
    2209             :                       const std::string &uuid,
    2210             :                       bool *match) {
    2211           0 :     SessionSloRuleStateMap::iterator  it;
    2212           0 :     bool is_logged = false;
    2213           0 :     it = session_rule_state_map_.find(uuid);
    2214           0 :     if (it != session_rule_state_map_.end()) {
    2215           0 :         *match = true;
    2216           0 :         if (it->second.ref_count == 0) {
    2217           0 :             is_logged = true;
    2218             :         }
    2219           0 :         it->second.ref_count++;
    2220           0 :         if (it->second.ref_count == it->second.rate) {
    2221           0 :             it->second.ref_count = 0;
    2222             :         }
    2223             :     }
    2224           0 :     return is_logged;
    2225             : }

Generated by: LCOV version 1.14