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: 445 1287 34.6 %
Date: 2026-08-03 02:19:58 Functions: 41 101 40.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14