LCOV - code coverage report
Current view: top level - vnsw/agent/vrouter/ksync - ksync_memory.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 18 142 12.7 %
Date: 2026-08-03 02:19:58 Functions: 2 12 16.7 %
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             : 
      32             : #include <vr_types.h>
      33             : #include <nl_util.h>
      34             : #include <vr_flow.h>
      35             : #include <ini_parser.h>
      36             : #include <vr_genetlink.h>
      37             : 
      38             : #include "ksync_init.h"
      39             : #include "ksync_flow_memory.h"
      40             : #include "sandesh_ksync.h"
      41             : #include "init/agent_param.h"
      42             : 
      43             : using namespace boost::asio::ip;
      44             : static const int kTestFlowTableSize = 131072 * sizeof(vr_flow_entry);
      45             : 
      46           6 : KSyncMemory::KSyncMemory(KSync *ksync, uint32_t minor_id) :
      47           6 :     ksync_(ksync),
      48           6 :     table_path_(),
      49           6 :     major_devid_(0),
      50           6 :     minor_devid_(minor_id),
      51           6 :     table_size_(0),
      52           6 :     table_entries_count_(0),
      53           6 :     audit_timer_(TimerManager::CreateTimer
      54           6 :                  (*(ksync->agent()->event_manager())->io_service(),
      55             :                   " Audit Timer",
      56             :                   ksync->agent()->task_scheduler()->GetTaskId(kTaskFlowAudit),
      57             :                   0)),
      58           6 :     audit_timeout_(0),
      59           6 :     audit_yield_(0),
      60           6 :     audit_interval_(0),
      61           6 :     audit_idx_(0),
      62          12 :     audit_list_() {
      63           6 : }
      64             : 
      65           6 : KSyncMemory::~KSyncMemory() {
      66           6 :     TimerManager::DeleteTimer(audit_timer_);
      67           6 : }
      68             : 
      69           0 : void KSyncMemory::Init() {
      70           0 :     audit_interval_ = kAuditYieldTimer;
      71           0 :     audit_timeout_ = kAuditTimeout;
      72           0 :     uint32_t table_count = table_entries_count_;
      73             :     // Compute number of entries to visit per timer interval so that complete
      74             :     // table can be visited in kAuditSweepTime
      75           0 :     uint32_t timer_per_sec = 1000 / kAuditYieldTimer;
      76           0 :     uint32_t timer_per_sweep = kAuditSweepTime * timer_per_sec;
      77           0 :     audit_yield_ = table_count / timer_per_sweep;
      78           0 :     if (audit_yield_ > kAuditYieldMax)
      79           0 :         audit_yield_ = kAuditYieldMax;
      80           0 :     if (audit_yield_ < kAuditYieldMin)
      81           0 :         audit_yield_ = kAuditYieldMin;
      82             : 
      83           0 :     audit_timer_->Start(audit_interval_,
      84             :                         boost::bind(&KSyncMemory::AuditProcess, this));
      85           0 : }
      86             : 
      87           0 : void KSyncMemory::Mmap(bool unlink_node, void *khpmem, bool kernel_mode) {
      88             :     // In case of non hugepage kernel mode,
      89             :     // Remove the existing /dev/ file first. We will add it again in vr_table_map
      90           0 :     if (!khpmem && unlink_node) {
      91           0 :         const char *error_msg = vr_table_unlink(table_path_.c_str());
      92           0 :         if (error_msg) {
      93           0 :             LOG(ERROR, "Error unmapping KSync memory: " << error_msg);
      94           0 :             assert(0);
      95             :         }
      96             :     }
      97           0 :     parse_ini_file();
      98             : 
      99             :     // Kernel hugepage present
     100           0 :     if (khpmem) {
     101           0 :         table_ = khpmem;
     102             :     } else {
     103             :         // DPDK or kernel without hugepage support
     104             :         const char *table_str;
     105           0 :         if (kernel_mode) {
     106           0 :             table_str = NULL;
     107             :         } else {
     108           0 :             table_str = table_path_.c_str();
     109             :         }
     110           0 :         const char *mmap_error_msg = vr_table_map(major_devid_, minor_devid_, table_str,
     111           0 :                                                   table_size_, &table_);
     112           0 :         if (mmap_error_msg) {
     113           0 :             LOG(ERROR, "Error mapping KSync memory. Device: " << table_path_ << "; " << mmap_error_msg);
     114           0 :             assert(0);
     115             :         }
     116           0 :         LOG(INFO, "Mem mapped dev file:" << table_path_.c_str() << " to addr:" << table_ << "\n");
     117             :     }
     118             : 
     119           0 :     table_entries_count_ = table_size_ / get_entry_size();
     120           0 :     SetTableSize();
     121           0 : }
     122             : 
     123           0 : int KSyncMemory::GetKernelTableSize() {
     124             :     struct nl_client *cl;
     125             :     int attr_len;
     126             :     int encode_len, ret;
     127             : 
     128           0 :     assert((cl = nl_register_client()) != NULL);
     129             : 
     130           0 :     assert(nl_socket(cl, AF_NETLINK, SOCK_DGRAM, NETLINK_GENERIC) > 0);
     131           0 :     assert(nl_connect(cl, 0, 0, 0) == 0);
     132             : 
     133           0 :     assert(vrouter_obtain_family_id(cl) > 0);
     134             : 
     135           0 :     assert(nl_build_nlh(cl, cl->cl_genl_family_id, NLM_F_REQUEST) == 0);
     136           0 :     assert(nl_build_genlh(cl, SANDESH_REQUEST, 0) == 0);
     137             : 
     138           0 :     attr_len = nl_get_attr_hdr_size();
     139             : 
     140           0 :     encode_len = EncodeReq(cl, attr_len);
     141           0 :     nl_build_attr(cl, encode_len, NL_ATTR_VR_MESSAGE_PROTOCOL);
     142           0 :     nl_update_nlh(cl);
     143             : 
     144           0 :     if ((ret = nl_sendmsg(cl)) < 0) {
     145           0 :         LOG(DEBUG, "Error requesting  Table message. Error : " << ret);
     146           0 :         assert(0);
     147             :     }
     148             : 
     149           0 :     while ((ret = nl_recvmsg(cl)) > 0) {
     150           0 :         KSyncSockNetlink::NetlinkDecoder(cl->cl_buf,
     151           0 :                                          KSyncSock::GetAgentSandeshContext(0));
     152             :     }
     153           0 :     nl_free_client(cl);
     154           0 :     return table_size_;
     155             : }
     156             : 
     157             : // Steps to map  table entry
     158             : // In case of non huge pages
     159             : // - Query the  table parameters from kernel
     160             : // - Create device /dev/ with major-num and minor-num
     161             : // - Map device memory
     162             : // In case of huge pages
     163             : // - Just use the huge page memory which is initialized
     164             : //   and passed to this function
     165           0 : void KSyncMemory::InitMem(void *hpmem) {
     166           0 :     GetKernelTableSize();
     167           0 :     Mmap(true, hpmem, true);
     168           0 :     return;
     169             : }
     170             : 
     171           0 : void KSyncMemory::InitTest() {
     172           0 :     assert(0);
     173             : }
     174             : 
     175           0 : void KSyncMemory::Shutdown() {
     176           0 :     assert(0);
     177             : }
     178             : 
     179           0 : bool KSyncMemory::AuditProcess() {
     180             :     // Get current time
     181           0 :     uint64_t t = UTCTimestampUsec();
     182             : 
     183           0 :     while (!audit_list_.empty()) {
     184           0 :         AuditEntry list_entry = audit_list_.front();
     185             :         // audit_list_ is sorted on last time of insertion in the list
     186             :         // So, break on finding first  entry that cannot be aged
     187           0 :         if ((t - list_entry.timeout) < audit_timeout_) {
     188             :             /* Wait for audit_timeout_ to create short  for the entry */
     189           0 :             break;
     190             :         }
     191           0 :         uint32_t idx = list_entry.audit_idx;
     192           0 :         uint32_t gen_id = list_entry.audit_gen_id;
     193           0 :         audit_list_.pop_front();
     194           0 :         DecrementHoldFlowCounter();
     195           0 :         CreateProtoAuditEntry(idx, gen_id);
     196             :     }
     197             : 
     198           0 :     uint32_t count = 0;
     199             :     uint8_t gen_id;
     200           0 :     assert(audit_yield_);
     201           0 :     while (count < audit_yield_) {
     202           0 :         if (IsInactiveEntry(audit_idx_, gen_id)) {
     203           0 :             IncrementHoldFlowCounter();
     204           0 :             audit_list_.push_back(AuditEntry(audit_idx_, gen_id, t));
     205             :         }
     206             : 
     207           0 :         count++;
     208           0 :         audit_idx_++;
     209           0 :         if (audit_idx_ == table_entries_count_) {
     210           0 :             UpdateAgentHoldFlowCounter();
     211           0 :             audit_idx_ = 0;
     212             :         }
     213             :     }
     214           0 :     return true;
     215             : }
     216             : 
     217           0 : void KSyncMemory::GetTableSize() {
     218             :     struct nl_client *cl;
     219             :     int attr_len;
     220             :     int encode_len;
     221             : 
     222           0 :     assert((cl = nl_register_client()) != NULL);
     223           0 :     cl->cl_genl_family_id = KSyncSock::GetNetlinkFamilyId();
     224           0 :     assert(nl_build_nlh(cl, cl->cl_genl_family_id, NLM_F_REQUEST) == 0);
     225           0 :     assert(nl_build_genlh(cl, SANDESH_REQUEST, 0) == 0);
     226             : 
     227           0 :     attr_len = nl_get_attr_hdr_size();
     228           0 :     encode_len = EncodeReq(cl, attr_len);
     229           0 :     nl_build_attr(cl, encode_len, NL_ATTR_VR_MESSAGE_PROTOCOL);
     230           0 :     nl_update_nlh(cl);
     231           0 :     string ksync_agent_vrouter_sock_path = KSYNC_AGENT_VROUTER_SOCK_PATH;
     232             :     ksync_agent_vrouter_sock_path =
     233           0 :     ksync_->agent()->params()->cat_is_agent_mocked()?
     234           0 :     ksync_->agent()->params()->cat_ksocketdir() + 
     235           0 :     "dpdk_netlink" : ksync_agent_vrouter_sock_path;
     236             : 
     237             : #ifdef AGENT_VROUTER_TCP
     238             :     tcp::socket socket(*(ksync_->agent()->event_manager()->io_service()));
     239             :     tcp::endpoint endpoint(ksync_->agent()->vrouter_server_ip(),
     240             :                            ksync_->agent()->vrouter_server_port());
     241             : #else
     242             :     boost::asio::local::stream_protocol::socket
     243           0 :         socket(*(ksync_->agent()->event_manager()->io_service()));
     244             :     boost::asio::local::stream_protocol::endpoint
     245           0 :         endpoint(ksync_agent_vrouter_sock_path);
     246             : #endif
     247           0 :     boost::system::error_code ec;
     248           0 :     socket.connect(endpoint, ec);
     249           0 :     if (ec) {
     250           0 :         assert(0);
     251             :     }
     252             : 
     253           0 :     socket.send(boost::asio::buffer(cl->cl_buf, cl->cl_buf_offset), 0, ec);
     254           0 :     if (ec) {
     255           0 :         assert(0);
     256             :     }
     257             : 
     258           0 :     uint32_t len_read = 0;
     259           0 :     uint32_t data_len = sizeof(struct nlmsghdr);
     260           0 :     while (len_read < data_len) {
     261           0 :         len_read = socket.read_some(boost::asio::buffer(cl->cl_buf + len_read,
     262           0 :                                                         cl->cl_buf_len), ec);
     263           0 :         if (ec) {
     264           0 :             assert(0);
     265             :         }
     266             : 
     267           0 :         if (len_read > sizeof(struct nlmsghdr)) {
     268           0 :             const struct nlmsghdr *nlh =
     269             :                 (const struct nlmsghdr *)((cl->cl_buf));
     270           0 :             data_len = nlh->nlmsg_len;
     271             :         }
     272             :     }
     273             : 
     274           0 :     KSyncSockNetlink::NetlinkDecoder(cl->cl_buf,
     275           0 :                                      KSyncSock::GetAgentSandeshContext(0));
     276           0 :     nl_free_client(cl);
     277           0 : }
     278             : 
     279           0 : void KSyncMemory::MapSharedMemory() {
     280           0 :     GetTableSize();
     281           0 :     Mmap(false, NULL, false);
     282           0 : }

Generated by: LCOV version 1.14