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

Generated by: LCOV version 1.14