LCOV - code coverage report
Current view: top level - vnsw/agent/pkt - flow_proto.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 357 543 65.7 %
Date: 2026-11-09 02:10:49 Functions: 34 51 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : #include <base/address_util.h>
       6             : #include <boost/functional/hash.hpp>
       7             : #include <init/agent_param.h>
       8             : #include <cmn/agent_stats.h>
       9             : #include <oper/agent_profile.h>
      10             : #include <vrouter/ksync/flowtable_ksync.h>
      11             : #include <vrouter/ksync/ksync_init.h>
      12             : #include <vrouter/ksync/ksync_flow_index_manager.h>
      13             : #include "vrouter/flow_stats/flow_stats_collector.h"
      14             : #include "flow_proto.h"
      15             : #include "flow_mgmt/flow_mgmt_dbclient.h"
      16             : #include "flow_mgmt.h"
      17             : #include "flow_event.h"
      18             : #include <strings.h>
      19             : #include "flow_entry.h"
      20             : 
      21             : static void UpdateStats(FlowEvent *event, FlowStats *stats);
      22             : 
      23           2 : FlowProto::FlowProto(Agent *agent, boost::asio::io_context &io) :
      24             :     Proto(agent, kTaskFlowEvent, PktHandler::FLOW, io),
      25           2 :     add_tokens_("Add Tokens", this, agent->flow_add_tokens()),
      26           2 :     ksync_tokens_("KSync` Tokens", this, agent->flow_ksync_tokens()),
      27           2 :     del_tokens_("Delete Tokens", this, agent->flow_del_tokens()),
      28           2 :     update_tokens_("Update Tokens", this, agent->flow_update_tokens()),
      29           2 :     flow_update_queue_(agent, this, &update_tokens_,
      30           2 :                        agent->params()->flow_task_latency_limit(), 16),
      31           2 :     use_vrouter_hash_(false), ipv4_trace_filter_(), ipv6_trace_filter_(),
      32           2 :     stats_(),
      33           2 :     port_table_manager_(agent, agent->params()->fabric_snat_hash_table_size()),
      34           2 :     stats_update_timer_(TimerManager::CreateTimer
      35           2 :         (*(agent->event_manager())->io_service(), "FlowStatsUpdateTimer",
      36           4 :          TaskScheduler::GetInstance()->GetTaskId(kTaskFlowStatsUpdate), 0)) {
      37           2 :     linklocal_flow_count_ = 0;
      38           2 :     agent->SetFlowProto(this);
      39           2 :     set_trace(false);
      40           2 :     uint16_t table_count = agent->flow_thread_count();
      41           2 :     assert(table_count >= kMinTableCount && table_count <= kMaxTableCount);
      42           4 :     for (uint8_t i = 0; i < table_count; i++) {
      43           2 :         flow_table_list_.push_back(new FlowTable(agent_, i));
      44             :     }
      45             : 
      46           4 :     for (uint32_t i = 0; i < table_count; i++) {
      47           2 :         uint16_t latency = agent->params()->flow_task_latency_limit();
      48             :         flow_event_queue_.push_back
      49           4 :             (new FlowEventQueue(agent, this, flow_table_list_[i],
      50             :                                 &add_tokens_, latency,
      51           2 :                                 FlowEventQueue::Queue::kMaxIterations));
      52             : 
      53             :         flow_tokenless_queue_.push_back
      54           4 :             (new FlowEventQueue(agent, this, flow_table_list_[i],
      55             :                                 NULL, latency,
      56           2 :                                 2 * FlowEventQueue::Queue::kMaxIterations));
      57             : 
      58             :         flow_delete_queue_.push_back
      59           4 :             (new DeleteFlowEventQueue(agent, this, flow_table_list_[i],
      60             :                                       &del_tokens_, latency,
      61           2 :                                       FlowEventQueue::Queue::kMaxIterations));
      62             : 
      63             :         flow_ksync_queue_.push_back
      64           4 :             (new KSyncFlowEventQueue(agent, this, flow_table_list_[i],
      65             :                                      &ksync_tokens_, latency,
      66           2 :                                      FlowEventQueue::Queue::kMaxIterations));
      67             :     }
      68           2 :     if (::getenv("USE_VROUTER_HASH") != NULL) {
      69           0 :         string opt = ::getenv("USE_VROUTER_HASH");
      70           0 :         if (opt == "" || strcasecmp(opt.c_str(), "false"))
      71           0 :             use_vrouter_hash_ = false;
      72             :         else
      73           0 :             use_vrouter_hash_ = true;
      74           0 :     }
      75           2 : }
      76             : 
      77           4 : FlowProto::~FlowProto() {
      78           2 :     STLDeleteValues(&flow_event_queue_);
      79           2 :     STLDeleteValues(&flow_tokenless_queue_);
      80           2 :     STLDeleteValues(&flow_delete_queue_);
      81           2 :     STLDeleteValues(&flow_ksync_queue_);
      82           2 :     STLDeleteValues(&flow_table_list_);
      83           4 : }
      84             : 
      85           2 : void FlowProto::Init() {
      86           2 :     agent_->stats()->RegisterFlowCountFn(boost::bind(&FlowProto::FlowCount,
      87             :                                                      this));
      88           4 :     for (uint16_t i = 0; i < flow_table_list_.size(); i++) {
      89           2 :         flow_table_list_[i]->Init();
      90             :     }
      91             : 
      92           2 :     AgentProfile *profile = agent_->oper_db()->agent_profile();
      93           2 :     profile->RegisterPktFlowStatsCb(boost::bind(&FlowProto::SetProfileData,
      94             :                                                 this, _1));
      95             : 
      96           2 :     ipv4_trace_filter_.Init(agent_->flow_trace_enable(), Address::INET);
      97           2 :     ipv6_trace_filter_.Init(agent_->flow_trace_enable(), Address::INET6);
      98           2 : }
      99             : 
     100           2 : void FlowProto::InitDone() {
     101           4 :     for (uint16_t i = 0; i < flow_table_list_.size(); i++) {
     102           2 :         flow_table_list_[i]->InitDone();
     103             :     }
     104           2 :     stats_update_timer_->Start(agent_->stats()->flow_stats_update_timeout(),
     105             :         boost::bind(&FlowProto::FlowStatsUpdate, this));
     106           2 : }
     107             : 
     108           2 : void FlowProto::Shutdown() {
     109           4 :     for (uint16_t i = 0; i < flow_table_list_.size(); i++) {
     110           2 :         flow_table_list_[i]->Shutdown();
     111             :     }
     112           4 :     for (uint32_t i = 0; i < flow_event_queue_.size(); i++) {
     113           2 :         flow_event_queue_[i]->Shutdown();
     114           2 :         flow_tokenless_queue_[i]->Shutdown();
     115           2 :         flow_delete_queue_[i]->Shutdown();
     116           2 :         flow_ksync_queue_[i]->Shutdown();
     117             :     }
     118           2 :     flow_update_queue_.Shutdown();
     119           2 :     if (stats_update_timer_) {
     120           2 :         stats_update_timer_->Cancel();
     121           2 :         TimerManager::DeleteTimer(stats_update_timer_);
     122             :     }
     123           2 : }
     124             : 
     125         750 : static std::size_t HashCombine(std::size_t hash, uint64_t val) {
     126         750 :     boost::hash_combine(hash, val);
     127         750 :     return hash;
     128             : }
     129             : 
     130         300 : static std::size_t HashIp(std::size_t hash, const IpAddress &ip) {
     131         300 :     if (ip.is_v6()) {
     132             :         uint64_t val[2];
     133           0 :         Ip6AddressToU64Array(ip.to_v6(), val, 2);
     134           0 :         hash = HashCombine(hash, val[0]);
     135           0 :         hash = HashCombine(hash, val[1]);
     136         300 :     } else if (ip.is_v4()) {
     137         300 :         hash = HashCombine(hash, ip.to_v4().to_ulong());
     138             :     } else {
     139           0 :         assert(0);
     140             :     }
     141         300 :     return hash;
     142             : }
     143             : 
     144             : // Get the thread to be used for the flow. We *try* to map forward and reverse
     145             : // flow to same thread with following,
     146             : //  if (sip < dip)
     147             : //      ip1 = sip
     148             : //      ip2 = dip
     149             : //  else
     150             : //      ip1 = dip
     151             : //      ip2 = sip
     152             : //  if (sport < dport)
     153             : //      port1 = sport
     154             : //      port2 = dport
     155             : //  else
     156             : //      port1 = dport
     157             : //      port2 = sport
     158             : //  field5 = proto
     159             : //  hash = HASH(ip1, ip2, port1, port2, proto)
     160             : //
     161             : // The algorithm above cannot ensure NAT flows belong to same thread.
     162         150 : uint16_t FlowProto::FlowTableIndex(const IpAddress &sip, const IpAddress &dip,
     163             :                                    uint8_t proto, uint16_t sport,
     164             :                                    uint16_t dport, uint32_t flow_handle) const {
     165         150 :     if (use_vrouter_hash_) {
     166           0 :         return (flow_handle/flow_table_list_.size()) % flow_table_list_.size();
     167             :     }
     168             : 
     169         150 :     std::size_t hash = 0;
     170         150 :     if (sip < dip) {
     171          46 :         hash = HashIp(hash, sip);
     172          46 :         hash = HashIp(hash, dip);
     173             :     } else {
     174         104 :         hash = HashIp(hash, dip);
     175         104 :         hash = HashIp(hash, sip);
     176             :     }
     177             : 
     178         150 :     if (sport < dport) {
     179          98 :         hash = HashCombine(hash, sport);
     180          98 :         hash = HashCombine(hash, dport);
     181             :     } else {
     182          52 :         hash = HashCombine(hash, dport);
     183          52 :         hash = HashCombine(hash, sport);
     184             :     }
     185         150 :     hash = HashCombine(hash, proto);
     186         150 :     return (hash % (flow_event_queue_.size()));
     187             : }
     188             : 
     189          75 : FlowHandler *FlowProto::AllocProtoHandler(PktInfoPtr info,
     190             :                                           boost::asio::io_context &io) {
     191          75 :     uint32_t index = FlowTableIndex(info->ip_saddr, info->ip_daddr,
     192          75 :                                     info->ip_proto, info->sport, info->dport,
     193          75 :                                     info->agent_hdr.cmd_param);
     194          75 :     return new FlowHandler(agent(), info, io, this, index);
     195             : }
     196             : 
     197          75 : bool FlowProto::Validate(PktInfo *msg) {
     198          75 :     if (msg->ip == NULL && msg->ip6 == NULL && msg->type != PktType::MESSAGE) {
     199           0 :         if (msg->family == Address::INET || msg->family == Address::INET6) {
     200           0 :             FLOW_TRACE(DetailErr, msg->agent_hdr.cmd_param,
     201             :                        msg->agent_hdr.ifindex,
     202             :                        msg->agent_hdr.vrf,
     203             :                        msg->ip_saddr.to_string(),
     204             :                        msg->ip_daddr.to_string(),
     205             :                        "Flow : Non-IP packet. Dropping", false);
     206             :         } else {
     207           0 :             assert(0);
     208             :         }
     209           0 :         return false;
     210             :     }
     211          75 :     return true;
     212             : }
     213             : 
     214           0 : FlowTable *FlowProto::GetFlowTable(const FlowKey &key,
     215             :                                    uint32_t flow_handle) const {
     216           0 :     uint32_t index = FlowTableIndex(key.src_addr, key.dst_addr, key.protocol,
     217           0 :                                     key.src_port, key.dst_port, flow_handle);
     218           0 :     return flow_table_list_[index];
     219             : }
     220             : 
     221          75 : bool FlowProto::Enqueue(PktInfoPtr msg) {
     222          75 :     if (Validate(msg.get()) == false) {
     223           0 :         return true;
     224             :     }
     225             : 
     226          75 :     FreeBuffer(msg.get());
     227          75 :     EnqueueFlowEvent(new FlowEvent(FlowEvent::VROUTER_FLOW_MSG, msg, NULL, 0));
     228          75 :     return true;
     229             : }
     230             : 
     231           0 : void FlowProto::DisableFlowEventQueue(uint32_t index, bool disabled) {
     232           0 :     flow_event_queue_[index]->set_disable(disabled);
     233           0 :     flow_tokenless_queue_[index]->set_disable(disabled);
     234           0 :     flow_delete_queue_[index]->set_disable(disabled);
     235           0 : }
     236             : 
     237           0 : void FlowProto::DisableFlowUpdateQueue(bool disabled) {
     238           0 :     flow_update_queue_.set_disable(disabled);
     239           0 : }
     240             : 
     241           0 : void FlowProto::DisableFlowKSyncQueue(uint32_t index, bool disabled) {
     242           0 :     flow_ksync_queue_[index]->set_disable(disabled);
     243           0 : }
     244             : 
     245           0 : size_t FlowProto::FlowUpdateQueueLength() {
     246           0 :     return flow_update_queue_.Length();
     247             : }
     248             : 
     249           0 : void FlowProto::DisableFlowDeleteQueue(uint32_t index, bool disabled) {
     250           0 :     flow_delete_queue_[index]->set_disable(disabled);
     251           0 : }
     252             : 
     253             : /////////////////////////////////////////////////////////////////////////////
     254             : // FlowTable related routines
     255             : /////////////////////////////////////////////////////////////////////////////
     256          20 : void FlowProto::FlushFlows() {
     257          40 :     for (uint16_t i = 0; i < flow_table_list_.size(); i++) {
     258          20 :         flow_table_list_[i]->DeleteAll();
     259             :     }
     260          20 : }
     261             : 
     262        1541 : FlowTable *FlowProto::GetTable(uint16_t index) const {
     263        1541 :     return flow_table_list_[index];
     264             : }
     265             : 
     266          69 : uint32_t FlowProto::FlowCount() const {
     267          69 :     uint32_t count = 0;
     268         138 :     for (uint16_t i = 0; i < flow_table_list_.size(); i++) {
     269          69 :         count += flow_table_list_[i]->Size();
     270             :     }
     271          69 :     return count;
     272             : }
     273             : 
     274           0 : void FlowProto::VnFlowCounters(const VnEntry *vn, uint32_t *in_count,
     275             :                                uint32_t *out_count) {
     276           0 :     *in_count = 0;
     277           0 :     *out_count = 0;
     278           0 :     if (vn == NULL)
     279           0 :         return;
     280             : 
     281             :     std::vector<FlowMgmtManager *>::const_iterator it =
     282           0 :         agent_->pkt()->flow_mgmt_manager_iterator_begin();
     283           0 :     while (it != agent_->pkt()->flow_mgmt_manager_iterator_end()) {
     284           0 :         (*it)->VnFlowCounters(vn, in_count, out_count);
     285           0 :         it++;
     286             :     }
     287             : }
     288             : 
     289        1427 : FlowEntry *FlowProto::Find(const FlowKey &key, uint32_t table_index) const {
     290        1427 :     return GetTable(table_index)->Find(key);
     291             : }
     292             : 
     293          75 : bool FlowProto::AddFlow(FlowEntry *flow) {
     294          75 :     FlowTable *table = flow->flow_table();
     295          75 :     table->Add(flow, flow->reverse_flow_entry());
     296          75 :     return true;
     297             : }
     298             : 
     299          37 : bool FlowProto::UpdateFlow(FlowEntry *flow) {
     300          37 :     FlowTable *table = flow->flow_table();
     301          37 :     table->Update(flow, flow->reverse_flow_entry());
     302          37 :     return true;
     303             : }
     304             : 
     305             : /////////////////////////////////////////////////////////////////////////////
     306             : // Flow Control Event routines
     307             : /////////////////////////////////////////////////////////////////////////////
     308        4364 : void FlowProto::EnqueueFlowEvent(FlowEvent *event) {
     309        4364 :     FlowEventQueueBase *queue = NULL;
     310        4364 :     switch (event->event()) {
     311          75 :     case FlowEvent::VROUTER_FLOW_MSG: {
     312          75 :         PktInfo *info = event->pkt_info().get();
     313         150 :         uint32_t index = FlowTableIndex(info->ip_saddr, info->ip_daddr,
     314          75 :                                         info->ip_proto, info->sport,
     315          75 :                                         info->dport,
     316          75 :                                         info->agent_hdr.cmd_param);
     317          75 :         queue = flow_event_queue_[index];
     318          75 :         break;
     319             :     }
     320             : 
     321          40 :     case FlowEvent::FLOW_MESSAGE: {
     322          40 :         FlowEntry *flow = event->flow();
     323          40 :         FlowTable *table = flow->flow_table();
     324          40 :         queue = flow_event_queue_[table->table_index()];
     325          40 :         break;
     326             :     }
     327             : 
     328          32 :     case FlowEvent::EVICT_FLOW: {
     329          32 :         FlowEntry *flow = event->flow();
     330          32 :         FlowTable *table = flow->flow_table();
     331          32 :         queue = flow_ksync_queue_[table->table_index()];
     332          32 :         break;
     333             :     }
     334             : 
     335         144 :     case FlowEvent::FREE_FLOW_REF: {
     336         144 :         FlowEntry *flow = event->flow();
     337         144 :         FlowTable *table = flow->flow_table();
     338         144 :         queue = flow_tokenless_queue_[table->table_index()];
     339         144 :         break;
     340             :     }
     341             : 
     342           0 :     case FlowEvent::AUDIT_FLOW: {
     343           0 :         FlowTable *table = GetFlowTable(event->get_flow_key(),
     344             :                                         event->flow_handle());
     345           0 :         queue = flow_event_queue_[table->table_index()];
     346           0 :         break;
     347             :     }
     348             : 
     349           0 :     case FlowEvent::GROW_FREE_LIST: {
     350           0 :         queue = flow_tokenless_queue_[event->table_index()];
     351           0 :         break;
     352             :     }
     353             : 
     354         378 :     case FlowEvent::KSYNC_EVENT: {
     355         378 :         FlowEventKSync *ksync_event = static_cast<FlowEventKSync *>(event);
     356             :         FlowTableKSyncEntry *ksync_entry =
     357         378 :             (static_cast<FlowTableKSyncEntry *> (ksync_event->ksync_entry()));
     358         378 :         FlowEntry *flow = ksync_entry->flow_entry().get();
     359         378 :         FlowTable *table = flow->flow_table();
     360         378 :         queue = flow_ksync_queue_[table->table_index()];
     361         378 :         break;
     362             :     }
     363             : 
     364           0 :     case FlowEvent::REENTRANT: {
     365           0 :         queue = flow_event_queue_[event->table_index()];
     366           0 :         break;
     367             :     }
     368             : 
     369           0 :     case FlowEvent::DELETE_FLOW: {
     370           0 :         FlowEntry *flow = event->flow();
     371           0 :         queue = flow_delete_queue_[flow->flow_table()->table_index()];
     372           0 :         break;
     373             :     }
     374             : 
     375        3494 :     case FlowEvent::FREE_DBENTRY: {
     376        3494 :         queue = flow_tokenless_queue_[0];
     377        3494 :         break;
     378             :     }
     379             : 
     380         201 :     case FlowEvent::DELETE_DBENTRY:
     381             :     case FlowEvent::RECOMPUTE_FLOW:
     382             :     case FlowEvent::REVALUATE_DBENTRY: {
     383         201 :         queue = &flow_update_queue_;
     384         201 :         break;
     385             :     }
     386             : 
     387           0 :     case FlowEvent::UNRESOLVED_FLOW_ENTRY: {
     388           0 :         FlowTable *table = event->flow()->flow_table();
     389           0 :         queue = flow_event_queue_[table->table_index()];
     390           0 :         break;
     391             :     }
     392           0 :     default:
     393           0 :         assert(0);
     394             :         break;
     395             :     }
     396             : 
     397        4364 :     UpdateStats(event, &stats_);
     398        4364 :     queue->Enqueue(event);
     399        4364 :     return;
     400             : }
     401             : 
     402        3750 : bool FlowProto::FlowEventHandler(FlowEvent *req, FlowTable *table) {
     403             :     // concurrency check to ensure all request are in right partitions
     404        3750 :     assert(table->ConcurrencyCheck(table->flow_task_id()) == true);
     405             : 
     406        3750 :     switch (req->event()) {
     407          75 :     case FlowEvent::VROUTER_FLOW_MSG: {
     408          75 :         ProcessProto(req->pkt_info());
     409          75 :         break;
     410             :     }
     411             : 
     412           0 :     case FlowEvent::REENTRANT: {
     413           0 :         FlowHandler *handler = new FlowHandler(agent(), req->pkt_info(), io_,
     414           0 :                                                this, table->table_index());
     415           0 :         RunProtoHandler(handler);
     416           0 :         break;
     417             :     }
     418             : 
     419          37 :     case FlowEvent::FLOW_MESSAGE: {
     420          37 :         FlowEntry *flow = req->flow();
     421             :         // process event only for forward flow with same gen_id
     422             :         // it may happen that after enqueued for recompute,
     423             :         // flow become reverse flow when the following sequence of
     424             :         // events occur.
     425             :         // 1. route is changed , flow is enqueued for recompute
     426             :         // 2. flow get evicted in vrouter
     427             :         // 3. traffic is received for reverse flow and get the same flow handle
     428             :         // 4. since flow handle is same , existing flow entries in agent won't
     429             :         //    be deleted but forward flow become reverse and vice versa
     430             :         //   added check to process events only if gen id matches,
     431             :         //   otherwise ignore it. added assertion not to process reverseflow
     432             :         //   at this stage as we only enqueue forward flows.
     433             : 
     434          74 :         if ((flow->flow_handle() == req->flow_handle()) &&
     435          74 :             (flow->gen_id() == req->gen_id()) &&
     436          74 :             (flow->is_flags_set(FlowEntry::ReverseFlow) == false)) {
     437          37 :             FlowTaskMsg *flow_msg = new FlowTaskMsg(flow);
     438          37 :             PktInfoPtr pkt_info(new PktInfo(PktHandler::FLOW, flow_msg));
     439          37 :             FlowHandler *handler = new FlowHandler(agent(), pkt_info, io_,
     440          37 :                                                this, table->table_index());
     441          37 :             RunProtoHandler(handler);
     442          37 :          }
     443          37 :         break;
     444             :     }
     445             : 
     446         144 :     case FlowEvent::FREE_FLOW_REF:
     447         144 :         break;
     448             : 
     449           0 :     case FlowEvent::GROW_FREE_LIST: {
     450           0 :         table->GrowFreeList();
     451           0 :         break;
     452             :     }
     453             : 
     454           0 :     case FlowEvent::AUDIT_FLOW: {
     455           0 :         FlowEntryPtr flow_ref = table->Find(req->get_flow_key());
     456           0 :         FlowEntry *flow  = flow_ref.get();
     457           0 :         if (flow == NULL) {
     458           0 :             FlowEntryPtr new_flow = FlowEntry::Allocate(req->get_flow_key(), table);
     459           0 :             new_flow->InitAuditFlow(req->flow_handle(), req->gen_id());
     460           0 :             new_flow->flow_table()->Add(new_flow.get(), NULL);
     461           0 :         } else {
     462             :             // scenario: forward flow trap is received , before installing
     463             :             // reverse flow, traffic received for reverse flow and trap is
     464             :             // dropped and not received in agent. vrouter returns
     465             :             // EEXIST error for reverse flow. flow entry is present
     466             :             // in flow table but it is in hold state.
     467             :             // take lock in forward and reverse flow order to avoid
     468             :             // deadlock.
     469             :             // EEXIST is seen only for reverse flows,
     470           0 :             if (flow && flow->is_flags_set(FlowEntry::ReverseFlow)) {
     471           0 :                 FLOW_LOCK(flow->reverse_flow_entry(), flow, req->event());
     472           0 :                 if (!(flow->deleted()) &&
     473           0 :                     flow->ksync_entry() &&
     474           0 :                     flow->ksync_entry()->ksync_response_error() == EEXIST) {
     475           0 :                     flow->MakeShortFlow(FlowEntry::SHORT_AUDIT_ENTRY);
     476             :                 }
     477           0 :             }
     478             :         }
     479           0 :         break;
     480           0 :     }
     481             : 
     482             :     // Check if flow-handle changed. This can happen if vrouter tries to
     483             :     // setup the flow which was evicted earlier
     484           0 :     case FlowEvent::UNRESOLVED_FLOW_ENTRY: {
     485           0 :         FlowEntry *flow = req->flow();
     486           0 :         flow->flow_table()->ProcessFlowEvent(req, flow,
     487             :                                              flow->reverse_flow_entry());
     488           0 :         break;
     489             :     }
     490             : 
     491           0 :     case FlowEvent::KSYNC_EVENT: {
     492           0 :         return FlowKSyncMsgHandler(req, table);
     493             :     }
     494             : 
     495        3494 :     case FlowEvent::FREE_DBENTRY: {
     496        6988 :         FlowMgmtManager *mgr = agent()->pkt()->flow_mgmt_manager(
     497        3494 :                                    req->table_index());
     498        3494 :         mgr->flow_mgmt_dbclient()->FreeDBState(req->db_entry(), req->gen_id());
     499        3494 :         break;
     500             :     }
     501             : 
     502           0 :     default: {
     503           0 :         assert(0);
     504             :         break;
     505             :     }
     506             :     }
     507             : 
     508        3750 :     return true;
     509             : }
     510             : 
     511         410 : bool FlowProto::FlowKSyncMsgHandler(FlowEvent *req, FlowTable *table) {
     512         410 :     FlowEventKSync *ksync_event = static_cast<FlowEventKSync *>(req);
     513             : 
     514             :     // concurrency check to ensure all request are in right partitions
     515         410 :     assert((table->ConcurrencyCheck(table->flow_ksync_task_id()) == true) ||
     516             :            (table->ConcurrencyCheck(table->flow_task_id()) == true));
     517             : 
     518         410 :     switch (req->event()) {
     519             :     // Flow was waiting for an index. Index is available now. Retry acquiring
     520             :     // the index
     521         378 :     case FlowEvent::KSYNC_EVENT: {
     522             :         FlowTableKSyncEntry *ksync_entry =
     523         378 :             (static_cast<FlowTableKSyncEntry *> (ksync_event->ksync_entry()));
     524         378 :         FlowEntry *flow = ksync_entry->flow_entry().get();
     525         378 :         flow->flow_table()->ProcessFlowEvent(req, flow,
     526             :                                              flow->reverse_flow_entry());
     527         378 :         break;
     528             :     }
     529             : 
     530          32 :     case FlowEvent::EVICT_FLOW: {
     531          32 :         FlowEntry *flow = req->flow();
     532          32 :         flow->flow_table()->ProcessFlowEvent(req, flow,
     533             :                                              flow->reverse_flow_entry());
     534          32 :         break;
     535             :     }
     536             : 
     537           0 :     default: {
     538           0 :         assert(0);
     539             :         break;
     540             :     }
     541             :     }
     542             : 
     543         410 :     return true;
     544             : }
     545             : 
     546         101 : bool FlowProto::FlowUpdateHandler(FlowEvent *req) {
     547         101 :     switch (req->event()) {
     548          53 :     case FlowEvent::DELETE_DBENTRY:
     549             :     case FlowEvent::REVALUATE_DBENTRY: {
     550          53 :         FlowEntry *flow = req->flow();
     551          53 :         flow->flow_table()->ProcessFlowEvent(req, flow,
     552             :                                              flow->reverse_flow_entry());
     553          53 :         break;
     554             :     }
     555             : 
     556          48 :     case FlowEvent::RECOMPUTE_FLOW: {
     557          48 :         FlowEntry *flow = req->flow();
     558          48 :         flow->flow_table()->ProcessFlowEvent(req, flow,
     559             :                                              flow->reverse_flow_entry());
     560          48 :         break;
     561             :     }
     562             : 
     563           0 :     default: {
     564           0 :         assert(0);
     565             :         break;
     566             :     }
     567             :     }
     568             : 
     569         101 :     return true;
     570             : }
     571             : 
     572           0 : bool FlowProto::FlowDeleteHandler(FlowEvent *req, FlowTable *table) {
     573             :     // concurrency check to ensure all request are in right partitions
     574             :     // flow-update-queue doenst happen table pointer. Skip concurrency check
     575             :     // for flow-update-queue
     576           0 :     if (table) {
     577           0 :         assert(table->ConcurrencyCheck(table->flow_delete_task_id()) == true);
     578             :     }
     579             : 
     580           0 :     switch (req->event()) {
     581           0 :     case FlowEvent::DELETE_FLOW: {
     582           0 :         FlowEntry *flow = req->flow();
     583           0 :         table->ProcessFlowEvent(req, flow, flow->reverse_flow_entry());
     584           0 :         break;
     585             :     }
     586             : 
     587           0 :     default: {
     588           0 :         assert(0);
     589             :         break;
     590             :     }
     591             :     }
     592             : 
     593           0 :     return true;
     594             : }
     595             : 
     596             : //////////////////////////////////////////////////////////////////////////////
     597             : // Utility methods to generate events
     598             : //////////////////////////////////////////////////////////////////////////////
     599           0 : void FlowProto::DeleteFlowRequest(FlowEntry *flow) {
     600           0 :     EnqueueFlowEvent(new FlowEvent(FlowEvent::DELETE_FLOW, flow));
     601           0 :     return;
     602             : }
     603             : 
     604           0 : void FlowProto::DeleteFlowRequest(const FlowKey &key) {
     605           0 :     CHECK_CONCURRENCY(kTaskFlowEvent);
     606           0 :     FlowEntry *flow = Find(key, 0);
     607           0 :     if (flow) {
     608           0 :         EnqueueFlowEvent(new FlowEvent(FlowEvent::DELETE_FLOW, flow));
     609             :     }
     610           0 : }
     611             : 
     612          32 : void FlowProto::EvictFlowRequest(FlowEntry *flow, uint32_t flow_handle,
     613             :                                  uint8_t gen_id, uint8_t evict_gen_id) {
     614             :     FlowEvent *event = new FlowEvent(FlowEvent::EVICT_FLOW, flow,
     615          32 :                                      flow_handle, gen_id, evict_gen_id);
     616          32 :     EnqueueFlowEvent(event);
     617          32 :    return;
     618             : }
     619             : 
     620           0 : void FlowProto::CreateAuditEntry(const FlowKey &key, uint32_t flow_handle,
     621             :                                  uint8_t gen_id) {
     622           0 :     EnqueueFlowEvent(new FlowEvent(FlowEvent::AUDIT_FLOW, key, flow_handle,
     623           0 :                                    gen_id));
     624           0 :     return;
     625             : }
     626             : 
     627             : 
     628           0 : void FlowProto::GrowFreeListRequest(FlowTable *table) {
     629           0 :     EnqueueFlowEvent(new FlowEvent(FlowEvent::GROW_FREE_LIST,
     630           0 :                                    table->table_index()));
     631           0 :     return;
     632             : }
     633             : 
     634         378 : void FlowProto::KSyncEventRequest(KSyncEntry *ksync_entry,
     635             :                                   KSyncEntry::KSyncEvent event,
     636             :                                   uint32_t flow_handle, uint8_t gen_id,
     637             :                                   int ksync_error, uint64_t evict_flow_bytes,
     638             :                                   uint64_t evict_flow_packets,
     639             :                                   int32_t evict_flow_oflow,
     640             :                                   uint32_t transaction_id) {
     641         756 :     EnqueueFlowEvent(new FlowEventKSync(ksync_entry, event, flow_handle,
     642             :                                         gen_id, ksync_error, evict_flow_bytes,
     643             :                                         evict_flow_packets, evict_flow_oflow,
     644         378 :                                         transaction_id));
     645         378 : }
     646             : 
     647          40 : void FlowProto::MessageRequest(FlowEntry *flow) {
     648          40 :     EnqueueFlowEvent(new FlowEvent(FlowEvent::FLOW_MESSAGE, flow,
     649          40 :                             flow->flow_handle(), flow->gen_id()));
     650          40 :     return;
     651             : }
     652             : 
     653             : // Flow management runs in parallel to flow processing. As a result,
     654             : // we need to ensure that last reference for flow will go away from
     655             : // kTaskFlowEvent context only. This is ensured by following 2 actions
     656             : //
     657             : // 1. On return from here reference to the flow is removed which can
     658             : //    potentially be last reference. So, enqueue a dummy request to
     659             : //    flow-table queue.
     660             : // 2. Due to OS scheduling, its possible that the request we are
     661             : //    enqueuing completes even before this function is returned. So,
     662             : //    drop the reference immediately after allocating the event
     663         144 : void FlowProto::ForceEnqueueFreeFlowReference(FlowEntryPtr &flow) {
     664             :     FlowEvent *event = new FlowEvent(FlowEvent::FREE_FLOW_REF,
     665         144 :                                      flow.get());
     666         144 :     flow.reset();
     667         144 :     EnqueueFlowEvent(event);
     668         144 : }
     669             : 
     670           0 : bool FlowProto::EnqueueReentrant(PktInfoPtr msg, uint8_t table_index) {
     671           0 :     EnqueueFlowEvent(new FlowEvent(FlowEvent::REENTRANT,
     672           0 :                                    msg, NULL, table_index));
     673           0 :     return true;
     674             : }
     675             : 
     676             : // Enqueue event to force revaluation of KSync entry
     677           0 : void FlowProto::EnqueueUnResolvedFlowEntry(FlowEntry *flow) {
     678           0 :     FlowEvent *event = new FlowEvent(FlowEvent::UNRESOLVED_FLOW_ENTRY, flow);
     679           0 :     EnqueueFlowEvent(event);
     680           0 : }
     681             : 
     682             : // Apply trace-filter for flow. Will not allow true-false transistions.
     683             : // That is, if flows are already marked for tracing, action is retained
     684         112 : bool FlowProto::ShouldTrace(const FlowEntry *flow, const FlowEntry *rflow) {
     685             :     // Handle case where flow is NULL. It can happen if Update is called
     686             :     // and flow is deleted between event-processing and calling
     687             :     // FlowTable::Update
     688         112 :     if (flow == NULL)
     689           0 :         return false;
     690             : 
     691         112 :     bool trace = flow->trace();
     692         112 :     if (rflow)
     693         112 :         trace |= rflow->trace();
     694             : 
     695         112 :     if (trace == false) {
     696             :         FlowTraceFilter *filter;
     697          93 :         if (flow->key().family == Address::INET) {
     698          93 :             filter = &ipv4_trace_filter_;
     699             :         } else {
     700           0 :             filter = &ipv6_trace_filter_;
     701             :         }
     702             : 
     703          93 :         trace = filter->Match(&flow->key());
     704          93 :         if (rflow && trace == false) {
     705           0 :             trace = filter->Match(&rflow->key());
     706             :         }
     707             :     }
     708             : 
     709         112 :     return trace;
     710             : }
     711             : 
     712             : //////////////////////////////////////////////////////////////////////////////
     713             : // Token Management routines
     714             : //////////////////////////////////////////////////////////////////////////////
     715         378 : TokenPtr FlowProto::GetToken(FlowEvent::Event event) {
     716         378 :     switch (event) {
     717         156 :     case FlowEvent::VROUTER_FLOW_MSG:
     718             :     case FlowEvent::AUDIT_FLOW:
     719             :     case FlowEvent::REENTRANT:
     720         156 :         return add_tokens_.GetToken(NULL);
     721             :         break;
     722             : 
     723          24 :     case FlowEvent::KSYNC_EVENT:
     724          24 :         return ksync_tokens_.GetToken(NULL);
     725             :         break;
     726             : 
     727         135 :     case FlowEvent::FLOW_MESSAGE:
     728             :     case FlowEvent::DELETE_DBENTRY:
     729             :     case FlowEvent::REVALUATE_DBENTRY:
     730             :     case FlowEvent::RECOMPUTE_FLOW:
     731         135 :         return update_tokens_.GetToken(NULL);
     732             :         break;
     733             : 
     734           0 :     case FlowEvent::DELETE_FLOW:
     735           0 :         return del_tokens_.GetToken(NULL);
     736             :         break;
     737             : 
     738          63 :     case FlowEvent::EVICT_FLOW:
     739             :     case FlowEvent::INVALID:
     740          63 :         break;
     741             : 
     742           0 :     default:
     743           0 :         assert(0);
     744             :         break;
     745             :     }
     746             : 
     747          63 :     return add_tokens_.GetToken(NULL);
     748             : }
     749             : 
     750         788 : bool FlowProto::TokenCheck(const FlowTokenPool *pool) const {
     751         788 :     return pool->TokenCheck();
     752             : }
     753             : 
     754           0 : void FlowProto::TokenAvailable(TokenPool *pool_base) {
     755           0 :     FlowTokenPool *pool = dynamic_cast<FlowTokenPool *>(pool_base);
     756           0 :     if (pool_base == NULL)
     757           0 :         return;
     758             : 
     759           0 :     pool->IncrementRestarts();
     760           0 :     if (pool == &add_tokens_) {
     761           0 :         for (uint32_t i = 0; i < flow_event_queue_.size(); i++) {
     762           0 :             flow_event_queue_[i]->MayBeStartRunner();
     763             :         }
     764             :     }
     765             : 
     766           0 :     if (pool == &ksync_tokens_) {
     767           0 :         for (uint32_t i = 0; i < flow_event_queue_.size(); i++) {
     768           0 :             flow_ksync_queue_[i]->MayBeStartRunner();
     769             :         }
     770             :     }
     771             : 
     772           0 :     if (pool == &del_tokens_) {
     773           0 :         for (uint32_t i = 0; i < flow_event_queue_.size(); i++) {
     774           0 :             flow_delete_queue_[i]->MayBeStartRunner();
     775             :         }
     776             :     }
     777             : 
     778           0 :     if (pool == &update_tokens_) {
     779           0 :         flow_update_queue_.MayBeStartRunner();
     780             :     }
     781             : }
     782             : 
     783             : //////////////////////////////////////////////////////////////////////////////
     784             : // Set profile information
     785             : //////////////////////////////////////////////////////////////////////////////
     786        4364 : void UpdateStats(FlowEvent *req, FlowStats *stats) {
     787        4364 :     switch (req->event()) {
     788          75 :     case FlowEvent::VROUTER_FLOW_MSG:
     789          75 :         stats->add_count_++;
     790          75 :         break;
     791          40 :     case FlowEvent::FLOW_MESSAGE:
     792          40 :         stats->flow_messages_++;
     793          40 :         break;
     794           0 :     case FlowEvent::DELETE_FLOW:
     795           0 :         stats->delete_count_++;
     796           0 :         break;
     797           0 :     case FlowEvent::AUDIT_FLOW:
     798           0 :         stats->audit_count_++;
     799           0 :         break;
     800         107 :     case FlowEvent::RECOMPUTE_FLOW:
     801         107 :         stats->recompute_count_++;
     802         107 :         break;
     803          17 :     case FlowEvent::REVALUATE_DBENTRY:
     804          17 :         stats->revaluate_count_++;
     805          17 :         break;
     806          32 :     case FlowEvent::EVICT_FLOW:
     807          32 :         stats->evict_count_++;
     808          32 :         break;
     809         378 :     case FlowEvent::KSYNC_EVENT: {
     810         378 :         stats->vrouter_responses_++;
     811         378 :         FlowEventKSync *ksync_event = static_cast<FlowEventKSync *>(req);
     812         378 :         if (ksync_event->ksync_error())
     813           0 :             stats->vrouter_error_++;
     814         378 :         break;
     815             :     }
     816        3715 :     default:
     817        3715 :         break;
     818             :     }
     819        4364 : }
     820             : 
     821          25 : static void SetFlowEventQueueStats(Agent *agent,
     822             :                                    const FlowEventQueueBase::Queue *queue,
     823             :                                    ProfileData::WorkQueueStats *stats) {
     824          25 :     stats->name_ = queue->Description();
     825          25 :     stats->queue_count_ = queue->Length();
     826          25 :     stats->enqueue_count_ = queue->NumEnqueues();
     827          25 :     stats->dequeue_count_ = queue->NumDequeues();
     828          25 :     stats->max_queue_count_ = queue->max_queue_len();
     829          25 :     stats->start_count_ = queue->task_starts();
     830          25 :     stats->busy_time_ = queue->busy_time();
     831          25 :     queue->set_measure_busy_time(agent->MeasureQueueDelay());
     832          25 :     if (agent->MeasureQueueDelay()) {
     833           0 :         queue->ClearStats();
     834             :     }
     835          25 : }
     836             : 
     837           5 : static void SetFlowMgmtQueueStats(Agent *agent,
     838             :                                   const FlowMgmtManager::FlowMgmtQueue *queue,
     839             :                                   ProfileData::WorkQueueStats *stats) {
     840           5 :     stats->name_ = queue->Description();
     841           5 :     stats->queue_count_ = queue->Length();
     842           5 :     stats->enqueue_count_ = queue->NumEnqueues();
     843           5 :     stats->dequeue_count_ = queue->NumDequeues();
     844           5 :     stats->max_queue_count_ = queue->max_queue_len();
     845           5 :     stats->start_count_ = queue->task_starts();
     846           5 :     stats->busy_time_ = queue->busy_time();
     847           5 :     queue->set_measure_busy_time(agent->MeasureQueueDelay());
     848           5 :     if (agent->MeasureQueueDelay())
     849           0 :         queue->ClearStats();
     850           5 : }
     851             : 
     852           5 : static void SetPktHandlerQueueStats(Agent *agent,
     853             :                                     const PktHandler::PktHandlerQueue *queue,
     854             :                                     ProfileData::WorkQueueStats *stats) {
     855           5 :     stats->name_ = queue->Description();
     856           5 :     stats->queue_count_ = queue->Length();
     857           5 :     stats->enqueue_count_ = queue->NumEnqueues();
     858           5 :     stats->dequeue_count_ = queue->NumDequeues();
     859           5 :     stats->max_queue_count_ = queue->max_queue_len();
     860           5 :     stats->start_count_ = queue->task_starts();
     861           5 :     stats->busy_time_ = queue->busy_time();
     862           5 :     queue->set_measure_busy_time(agent->MeasureQueueDelay());
     863           5 :     if (agent->MeasureQueueDelay())
     864           0 :         queue->ClearStats();
     865           5 : }
     866             : 
     867           5 : void FlowProto::SetProfileData(ProfileData *data) {
     868           5 :     data->flow_.flow_count_ = FlowCount();
     869           5 :     data->flow_.add_count_ = stats_.add_count_;
     870           5 :     data->flow_.del_count_ = stats_.delete_count_;
     871           5 :     data->flow_.audit_count_ = stats_.audit_count_;
     872           5 :     data->flow_.reval_count_ = stats_.revaluate_count_;
     873           5 :     data->flow_.recompute_count_ = stats_.recompute_count_;
     874           5 :     data->flow_.vrouter_responses_ = stats_.vrouter_responses_;
     875           5 :     data->flow_.vrouter_error_ = stats_.vrouter_error_;
     876           5 :     data->flow_.evict_count_ = stats_.evict_count_;
     877             : 
     878           5 :     PktModule *pkt = agent()->pkt();
     879           5 :     std::vector<FlowMgmtManager *> mgr_list = pkt->flow_mgmt_manager_list();
     880             : 
     881           5 :     data->flow_.flow_event_queue_.resize(flow_table_list_.size());
     882           5 :     data->flow_.flow_delete_queue_.resize(flow_table_list_.size());
     883           5 :     data->flow_.flow_tokenless_queue_.resize(flow_table_list_.size());
     884           5 :     data->flow_.flow_ksync_queue_.resize(flow_table_list_.size());
     885          10 :     for (uint16_t i = 0; i < flow_table_list_.size(); i++) {
     886           5 :         SetFlowMgmtQueueStats(agent(), mgr_list[i]->request_queue(),
     887             :                               &data->flow_.flow_mgmt_queue_);
     888           5 :         SetFlowEventQueueStats(agent(), flow_event_queue_[i]->queue(),
     889           5 :                                &data->flow_.flow_event_queue_[i]);
     890           5 :         SetFlowEventQueueStats(agent(), flow_delete_queue_[i]->queue(),
     891           5 :                                &data->flow_.flow_delete_queue_[i]);
     892           5 :         SetFlowEventQueueStats(agent(), flow_tokenless_queue_[i]->queue(),
     893           5 :                                &data->flow_.flow_tokenless_queue_[i]);
     894           5 :         SetFlowEventQueueStats(agent(), flow_ksync_queue_[i]->queue(),
     895           5 :                                &data->flow_.flow_ksync_queue_[i]);
     896             :     }
     897           5 :     SetFlowEventQueueStats(agent(), flow_update_queue_.queue(),
     898             :                            &data->flow_.flow_update_queue_);
     899             :     const PktHandler::PktHandlerQueue *pkt_queue =
     900           5 :         pkt->pkt_handler()->work_queue();
     901           5 :     SetPktHandlerQueueStats(agent(), pkt_queue,
     902             :                             &data->flow_.pkt_handler_queue_);
     903             : 
     904           5 :     data->flow_.token_stats_.add_tokens_ = add_tokens_.token_count();
     905           5 :     data->flow_.token_stats_.add_failures_ = add_tokens_.failures();
     906           5 :     data->flow_.token_stats_.add_restarts_ = add_tokens_.restarts();
     907           5 :     data->flow_.token_stats_.ksync_tokens_ = ksync_tokens_.token_count();
     908           5 :     data->flow_.token_stats_.ksync_failures_ = ksync_tokens_.failures();
     909           5 :     data->flow_.token_stats_.ksync_restarts_ = ksync_tokens_.restarts();
     910           5 :     data->flow_.token_stats_.update_tokens_ = update_tokens_.token_count();
     911           5 :     data->flow_.token_stats_.update_failures_ = update_tokens_.failures();
     912           5 :     data->flow_.token_stats_.update_restarts_ = update_tokens_.restarts();
     913           5 :     data->flow_.token_stats_.del_tokens_ = del_tokens_.token_count();
     914           5 :     data->flow_.token_stats_.del_failures_ = del_tokens_.failures();
     915           5 :     data->flow_.token_stats_.del_restarts_ = del_tokens_.restarts();
     916           5 : }
     917             : 
     918           0 : bool FlowProto::FlowStatsUpdate() const {
     919           0 :     agent_->stats()->UpdateFlowMinMaxStats(agent_->stats()->flow_created(),
     920           0 :                                            agent_->stats()->added());
     921           0 :     agent_->stats()->UpdateFlowMinMaxStats(agent_->stats()->flow_aged(),
     922           0 :                                            agent_->stats()->deleted());
     923           0 :     return true;
     924             : }
     925             : 
     926           0 : void FlowProto::InterfaceFlowCount(const Interface *intf, uint64_t *created,
     927             :                                    uint64_t *aged,
     928             :                                    uint32_t *active_flows) const {
     929           0 :     *created = 0;
     930           0 :     *aged = 0;
     931           0 :     *active_flows = 0;
     932           0 :     if (intf == NULL)
     933           0 :         return;
     934             :     std::vector<FlowMgmtManager *>::const_iterator it =
     935           0 :         agent_->pkt()->flow_mgmt_manager_iterator_begin();
     936           0 :     while (it != agent_->pkt()->flow_mgmt_manager_iterator_end()) {
     937           0 :         (*it)->InterfaceFlowCount(intf, created, aged, active_flows);
     938           0 :         it++;
     939             :     }
     940             : }

Generated by: LCOV version 1.14