LCOV - code coverage report
Current view: top level - vnsw/agent/vrouter/ksync - ksync_flow_memory.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 64 174 36.8 %
Date: 2026-08-03 02:19:58 Functions: 12 24 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <sys/socket.h>
       6             : #if defined(__linux__)
       7             : #include <linux/netlink.h>
       8             : #endif
       9             : #include <fcntl.h>
      10             : #include <sys/mman.h>
      11             : #include <sys/types.h>
      12             : #include <sys/ipc.h>
      13             : #include <sys/shm.h>
      14             : #include <asm/types.h>
      15             : #include <boost/asio.hpp>
      16             : 
      17             : #include <base/timer.h>
      18             : #include <base/task_trigger.h>
      19             : #include <base/address_util.h>
      20             : #include <cmn/agent_cmn.h>
      21             : #include <services/services_init.h>
      22             : #include <uve/stats_collector.h>
      23             : #include <services/icmp_error_proto.h>
      24             : #include <pkt/flow_proto.h>
      25             : #include <ksync/ksync_index.h>
      26             : #include <ksync/ksync_entry.h>
      27             : #include <ksync/ksync_object.h>
      28             : #include <ksync/ksync_netlink.h>
      29             : #include <ksync/ksync_sock.h>
      30             : #include <ksync/ksync_sock_user.h>
      31             : #include <vrouter/flow_stats/flow_stats_collector.h>
      32             : 
      33             : #include <vr_types.h>
      34             : #include <nl_util.h>
      35             : #include <vr_flow.h>
      36             : #include <vr_genetlink.h>
      37             : 
      38             : #include "ksync_init.h"
      39             : #include "ksync_flow_memory.h"
      40             : #include "sandesh_ksync.h"
      41             : 
      42             : using namespace boost::asio::ip;
      43             : static const int kTestFlowTableSize = 131072 * sizeof(vr_flow_entry);
      44             : 
      45           3 : KSyncFlowMemory::KSyncFlowMemory(KSync *ksync, uint32_t minor_id) :
      46           3 :     KSyncMemory(ksync, minor_id) {
      47           3 :     table_path_ = FLOW_TABLE_DEV;
      48           3 :     hold_flow_counter_ = 0;
      49           3 : }
      50             : 
      51           0 : void KSyncFlowMemory::Init() {
      52           0 :     IcmpErrorProto *proto = ksync_->agent()->services()->icmp_error_proto();
      53           0 :     proto->Register(boost::bind(&KSyncFlowMemory::GetFlowKey, this, _1, _2, _3));
      54             : 
      55           0 :     KSyncMemory::Init();
      56           0 : }
      57             : 
      58           0 : int KSyncFlowMemory::EncodeReq(struct nl_client *cl, uint32_t attr_len) {
      59             :     int encode_len, error;
      60             : 
      61           0 :     vr_flow_table_data info;
      62           0 :     info.set_ftable_op(flow_op::FLOW_TABLE_GET);
      63           0 :     info.set_ftable_size(0);
      64           0 :     info.set_ftable_dev(0);
      65           0 :     info.set_ftable_file_path("");
      66           0 :     info.set_ftable_processed(0);
      67           0 :     info.set_ftable_hold_oflows(0);
      68           0 :     info.set_ftable_added(0);
      69           0 :     info.set_ftable_cpus(0);
      70           0 :     info.set_ftable_created(0);
      71           0 :     info.set_ftable_oflow_entries(0);
      72           0 :     encode_len = info.WriteBinary(nl_get_buf_ptr(cl) + attr_len,
      73             :                                   nl_get_buf_len(cl), &error);
      74           0 :     return encode_len;
      75           0 : }
      76             : 
      77           3 : int KSyncFlowMemory::get_entry_size() {
      78           3 :     return sizeof(vr_flow_entry);
      79             : }
      80             : 
      81           3 : void KSyncFlowMemory::SetTableSize() {
      82           3 :     ksync_->agent()->set_flow_table_size(table_entries_count_);
      83           3 :     flow_table_ = static_cast<vr_flow_entry *>(table_);
      84           3 : }
      85             : 
      86           0 : void KSyncFlowMemory::CreateProtoAuditEntry(uint32_t idx, uint8_t gen_id) {
      87           0 :     const vr_flow_entry *ventry = GetKernelFlowEntry(idx, false);
      88             :     // Audit and remove  entry if its still in HOLD state
      89           0 :     if (ventry && ventry->fe_gen_id == gen_id &&
      90           0 :         ventry->fe_action == VR_FLOW_ACTION_HOLD) {
      91           0 :         IpAddress sip, dip;
      92           0 :         VrFlowToIp(ventry, &sip, &dip);
      93           0 :         FlowKey key(ventry->fe_key.flow_nh_id, sip, dip,
      94           0 :                 ventry->fe_key.flow_proto,
      95           0 :                 ntohs(ventry->fe_key.flow_sport),
      96           0 :                 ntohs(ventry->fe_key.flow_dport));
      97             : 
      98           0 :         FlowProto *proto = ksync_->agent()->pkt()->get_flow_proto();
      99           0 :         proto->CreateAuditEntry(key, idx, gen_id);
     100             :     }
     101           0 : }
     102             : 
     103           0 : void KSyncFlowMemory::DecrementHoldFlowCounter() {
     104           0 :     hold_flow_counter_--;
     105           0 :     return;
     106             : }
     107             : 
     108           0 : void KSyncFlowMemory::IncrementHoldFlowCounter() {
     109           0 :     hold_flow_counter_++;
     110           0 :     return;
     111             : }
     112             : 
     113           0 : void KSyncFlowMemory::UpdateAgentHoldFlowCounter() {
     114           0 :     ksync_->agent()->stats()->update_hold_flow_count(hold_flow_counter_);
     115           0 :     hold_flow_counter_ = 0;
     116           0 :     return;
     117             : }
     118             : 
     119           0 : bool KSyncFlowMemory::IsInactiveEntry(uint32_t audit_idx, uint8_t &gen_id) {
     120             :     const vr_flow_entry *vflow_entry =
     121           0 :         GetKernelFlowEntry(audit_idx, false);
     122           0 :     if (vflow_entry && vflow_entry->fe_action == VR_FLOW_ACTION_HOLD) {
     123           0 :         gen_id = vflow_entry->fe_gen_id;
     124           0 :         return true;
     125             :     }
     126           0 :     return false;
     127             : }
     128             : 
     129           0 : void KSyncFlowMemory::VrFlowToIp(const vr_flow_entry *kflow, IpAddress *sip,
     130             :                                  IpAddress *dip) {
     131           0 :     if (kflow->fe_key.flow_family == AF_INET) {
     132           0 :         *sip = Ip4Address(ntohl(kflow->fe_key.key_u.ip4_key.ip4_sip));
     133           0 :         *dip = Ip4Address(ntohl(kflow->fe_key.key_u.ip4_key.ip4_dip));
     134             :     } else {
     135           0 :         const unsigned char *k_sip = kflow->fe_key.key_u.ip6_key.ip6_sip;
     136           0 :         const unsigned char *k_dip = kflow->fe_key.key_u.ip6_key.ip6_dip;
     137             :         Ip6Address::bytes_type sbytes;
     138             :         Ip6Address::bytes_type dbytes;
     139           0 :         for (int i = 0; i < 16; i++) {
     140           0 :             sbytes[i] = k_sip[i];
     141           0 :             dbytes[i] = k_dip[i];
     142             :         }
     143           0 :         *sip = Ip6Address(sbytes);
     144           0 :         *dip = Ip6Address(dbytes);
     145             :     }
     146           0 : }
     147             : 
     148           0 : void KSyncFlowMemory::KFlow2FlowKey(const vr_flow_entry *kflow,
     149             :                                     FlowKey *key) const {
     150           0 :     key->nh = kflow->fe_key.flow4_nh_id;
     151           0 :     Address::Family family = (kflow->fe_key.flow_family == AF_INET)?
     152             :                               Address::INET : Address::INET6;
     153           0 :     VrFlowToIp(kflow, &key->src_addr, &key->dst_addr);
     154           0 :     key->src_port = ntohs(kflow->fe_key.flow4_sport);
     155           0 :     key->dst_port = ntohs(kflow->fe_key.flow4_dport);
     156           0 :     key->protocol = kflow->fe_key.flow4_proto;
     157           0 :     key->family = family;
     158           0 : }
     159             : 
     160          63 : const vr_flow_entry *KSyncFlowMemory::GetValidKFlowEntry(const FlowKey &key,
     161             :                                                          uint32_t idx,
     162             :                                                          uint8_t gen_id) const {
     163          63 :     const vr_flow_entry *kflow = GetKernelFlowEntry(idx, false);
     164          63 :     if (!kflow) {
     165          25 :         return NULL;
     166             :     }
     167          38 :     if (key.protocol == IPPROTO_TCP) {
     168           0 :         FlowKey rhs;
     169           0 :         KFlow2FlowKey(kflow, &rhs);
     170           0 :         if (!key.IsEqual(rhs)) {
     171           0 :             return NULL;
     172             :         }
     173           0 :         if (kflow->fe_gen_id != gen_id) {
     174           0 :             return NULL;
     175             :         }
     176             :     }
     177          38 :     return kflow;
     178             : }
     179             : 
     180         145 : const vr_flow_entry *KSyncFlowMemory::GetKernelFlowEntry
     181             :     (uint32_t idx, bool ignore_active_status) const {
     182         145 :     if (idx == FlowEntry::kInvalidFlowHandle) {
     183           3 :         return NULL;
     184             :     }
     185             : 
     186         142 :     if (idx >= table_entries_count_) {
     187             :         /* if index is outside the range of flow table entries return NULL */
     188           0 :         return NULL;
     189             :     }
     190             : 
     191         142 :     if (ignore_active_status) {
     192           0 :         return &flow_table_[idx];
     193             :     }
     194             : 
     195         142 :     if (flow_table_[idx].fe_flags & VR_FLOW_FLAG_ACTIVE) {
     196          91 :         return &flow_table_[idx];
     197             :     }
     198          51 :     return NULL;
     199             : }
     200             : 
     201           0 : bool KSyncFlowMemory::GetFlowKey(uint32_t index, FlowKey *key, bool *is_nat_flow) {
     202           0 :     const vr_flow_entry *kflow = GetKernelFlowEntry(index, false);
     203           0 :     if (!kflow) {
     204           0 :         return false;
     205             :     }
     206           0 :     key->nh = kflow->fe_key.flow4_nh_id;
     207           0 :     Address::Family family = (kflow->fe_key.flow_family == AF_INET)?
     208             :                               Address::INET : Address::INET6;
     209           0 :     VrFlowToIp(kflow, &key->src_addr, &key->dst_addr);
     210           0 :     key->src_port = ntohs(kflow->fe_key.flow4_sport);
     211           0 :     key->dst_port = ntohs(kflow->fe_key.flow4_dport);
     212           0 :     key->protocol = kflow->fe_key.flow4_proto;
     213           0 :     key->family = family;
     214           0 :     if (kflow->fe_action == VR_FLOW_ACTION_NAT) {
     215           0 :         *is_nat_flow = true;
     216             :     } else {
     217           0 :         *is_nat_flow = false;
     218             :     }
     219           0 :     return true;
     220             : }
     221             : 
     222           0 : bool KSyncFlowMemory::IsEvictionMarked(const vr_flow_entry *entry,
     223             :                                        uint16_t flags) const {
     224           0 :     if (!entry) {
     225           0 :         return false;
     226             :     }
     227           0 :     if (flags & VR_FLOW_FLAG_EVICTED) {
     228           0 :         return true;
     229             :     }
     230           0 :     return false;
     231             : }
     232             : 
     233          44 : const vr_flow_entry *KSyncFlowMemory::GetKFlowStats(const FlowKey &key,
     234             :                                                     uint32_t idx,
     235             :                                                     uint8_t gen_id,
     236             :                                                     vr_flow_stats *stat) const {
     237          44 :     const vr_flow_entry *kflow = GetValidKFlowEntry(key, idx, gen_id);
     238          44 :     if (!kflow) {
     239          25 :         return NULL;
     240             :     }
     241          19 :     *stat = kflow->fe_stats;
     242          19 :     kflow = GetValidKFlowEntry(key, idx, gen_id);
     243          19 :     return kflow;
     244             : }
     245             : 
     246          53 : void KSyncFlowMemory::ReadFlowInfo(const vr_flow_entry *kflow,
     247             :                                    vr_flow_stats *stat, KFlowData *info) const {
     248          53 :     *stat = kflow->fe_stats;
     249          53 :     info->underlay_src_port = kflow->fe_udp_src_port;
     250          53 :     info->tcp_flags = kflow->fe_tcp_flags;
     251          53 :     info->flags = kflow->fe_flags;
     252          53 : }
     253             : 
     254          82 : const vr_flow_entry *KSyncFlowMemory::GetKFlowStatsAndInfo(const FlowKey &key,
     255             :                                                            uint32_t idx,
     256             :                                                            uint8_t gen_id,
     257             :                                                            vr_flow_stats *stats,
     258             :                                                            KFlowData *info)
     259             :     const {
     260          82 :     const vr_flow_entry *kflow = GetKernelFlowEntry(idx, false);
     261          82 :     if (!kflow) {
     262          29 :         return NULL;
     263             :     }
     264          53 :     if (key.protocol == IPPROTO_TCP) {
     265           0 :         FlowKey rhs;
     266           0 :         KFlow2FlowKey(kflow, &rhs);
     267           0 :         if (!key.IsEqual(rhs)) {
     268           0 :             return NULL;
     269             :         }
     270             : 
     271           0 :         ReadFlowInfo(kflow, stats, info);
     272             : 
     273           0 :         if (kflow->fe_gen_id != gen_id) {
     274           0 :             return NULL;
     275             :         }
     276             :     } else {
     277          53 :         ReadFlowInfo(kflow, stats, info);
     278             :     }
     279          53 :     return kflow;
     280             : }
     281             : 
     282           3 : void KSyncFlowMemory::InitTest() {
     283           3 :     table_ = KSyncSockTypeMap::FlowMmapAlloc(kTestFlowTableSize);
     284           3 :     memset(table_, 0, kTestFlowTableSize);
     285           3 :     table_entries_count_ = kTestFlowTableSize / get_entry_size();
     286           3 :     audit_yield_ = table_entries_count_;
     287           3 :     audit_timeout_ = 100 * 1000; // timout immediately.
     288           3 :     SetTableSize();
     289           3 : }
     290             : 
     291           3 : void KSyncFlowMemory::Shutdown() {
     292           3 :     KSyncSockTypeMap::FlowMmapFree();
     293           3 : }
     294             : 
     295         144 : void vr_flow_req::Process(SandeshContext *context) {
     296         144 :     AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
     297         144 :     ioc->FlowMsgHandler(this);
     298         144 : }
     299             : 
     300         144 : void vr_flow_response::Process(SandeshContext *context) {
     301         144 :     AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
     302         144 :     ioc->FlowResponseHandler(this);
     303         144 : }
     304             : 
     305           0 : void vr_flow_table_data::Process(SandeshContext *context) {
     306           0 :     AgentSandeshContext *ioc = static_cast<AgentSandeshContext *>(context);
     307           0 :     ioc->FlowTableInfoHandler(this);
     308           0 : }

Generated by: LCOV version 1.14