LCOV - code coverage report
Current view: top level - ksync - ksync_sock_tcp.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 197 0.0 %
Date: 2026-11-09 02:10:49 Functions: 0 27 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "ksync_sock.h"
       7             : 
       8             : #include <boost/asio.hpp>
       9             : #include <boost/bind/bind.hpp>
      10             : 
      11             : using namespace boost::asio;
      12             : using namespace boost::placeholders;
      13             : 
      14             : /////////////////////////////////////////////////////////////////////////////
      15             : // KSyncSockTcp routines
      16             : /////////////////////////////////////////////////////////////////////////////
      17             : //TCP socket class for interacting with vrouter
      18           0 : KSyncSockTcp::KSyncSockTcp(EventManager *evm,
      19           0 :     boost::asio::ip::address ip_address, int port) : TcpServer(evm), evm_(evm),
      20           0 :     session_(NULL), server_ep_(ip_address, port), connect_complete_(false) {
      21             : 
      22           0 :     reset_use_wait_tree();
      23           0 :     set_process_data_inline();
      24           0 :     if (rx_buff_ == NULL) {
      25           0 :         rx_buff_ = new char[kBufLen];
      26             :     }
      27           0 :     rx_buff_rem_ = new char[kBufLen];
      28           0 :     remain_ = 0;
      29             : 
      30           0 :     session_ = CreateSession();
      31           0 :     Connect(session_, server_ep_);
      32           0 : }
      33             : 
      34           0 : void KSyncSockTcp::Init(EventManager *evm, boost::asio::ip::address ip_addr,
      35             :                         int port, const std::string &cpu_pin_policy) {
      36           0 :     KSyncSock::SetSockTableEntry(new KSyncSockTcp(evm, ip_addr, port));
      37           0 :     SetNetlinkFamilyId(10);
      38           0 :     KSyncSock::Init(false, cpu_pin_policy);
      39           0 : }
      40             : 
      41           0 : TcpSession* KSyncSockTcp::AllocSession(Socket *socket) {
      42           0 :     TcpSession *session = new KSyncSockTcpSession(this, socket, false);
      43           0 :     session->set_observer(boost::bind(&KSyncSockTcp::OnSessionEvent,
      44             :                                       this, _1, _2));
      45           0 :     return session;
      46             : }
      47             : 
      48           0 : uint32_t KSyncSockTcp::GetSeqno(char *data) {
      49           0 :     return GetNetlinkSeqno(data);
      50             : }
      51             : 
      52           0 : bool KSyncSockTcp::IsMoreData(char *data) {
      53           0 :     return NetlinkMsgDone(data);
      54             : }
      55             : 
      56           0 : size_t KSyncSockTcp::SendTo(KSyncBufferList *iovec, uint32_t seq_no) {
      57           0 :     size_t len = 0, ret;
      58             :     struct msghdr msg;
      59           0 :     struct iovec iov[max_bulk_msg_count_*2];
      60             :     int i, fd;
      61             : 
      62           0 :     memset(&msg, 0, sizeof(msg));
      63           0 :     msg.msg_iov = iov;
      64             : 
      65           0 :     ResetNetlink(nl_client_);
      66           0 :     int offset = nl_client_->cl_buf_offset;
      67           0 :     UpdateNetlink(nl_client_, bulk_buf_size_, seq_no);
      68             : 
      69           0 :     KSyncBufferList::iterator it = iovec->begin();
      70           0 :     iovec->insert(it, buffer((char *)nl_client_->cl_buf, offset));
      71             : 
      72           0 :     int count = iovec->size();
      73           0 :     for(i = 0; i < count; i++) {
      74           0 :         mutable_buffers_1 buf = iovec->at(i);
      75           0 :         size_t buf_size = boost::asio::buffer_size(buf);
      76           0 :         void* cbuf = boost::asio::buffer_cast<void*>(buf);
      77           0 :         len += buf_size;
      78           0 :         iov[i].iov_base = cbuf;
      79           0 :         iov[i].iov_len = buf_size;
      80             :     }
      81             : 
      82           0 :     msg.msg_iovlen = i;
      83           0 :     fd = tcp_socket_->native_handle();
      84           0 :     ret = sendmsg(fd, &msg, 0);
      85           0 :     if (ret != len) {
      86           0 :         LOG(ERROR, "sendmsg failure " << ret << "len " << len);
      87             :     }
      88           0 :     return len;
      89           0 : }
      90             : 
      91           0 : void KSyncSockTcp::AsyncSendTo(KSyncBufferList *iovec, uint32_t seq_no,
      92             :                                HandlerCb cb) {
      93           0 :     SendTo(iovec, seq_no);
      94           0 :     return;
      95             : }
      96             : 
      97           0 : bool KSyncSockTcp::Validate(char *data) {
      98           0 :     return ValidateNetlink(data);
      99             : }
     100             : 
     101           0 : bool KSyncSockTcp::Decoder(char *data, AgentSandeshContext *context) {
     102           0 :     KSyncSockNetlink::NetlinkDecoder(data, context);
     103           0 :     return true;
     104             : }
     105             : 
     106           0 : bool KSyncSockTcp::BulkDecoder(char *data,
     107             :                                KSyncBulkSandeshContext *bulk_sandesh_context) {
     108             :     // Get sandesh buffer and buffer-length
     109           0 :     uint32_t buf_len = 0;
     110           0 :     char *buf = NULL;
     111           0 :     GetNetlinkPayload(data, &buf, &buf_len);
     112           0 :     return bulk_sandesh_context->Decoder(buf, buf_len, NLA_ALIGNTO, IsMoreData(data));
     113             : }
     114             : 
     115           0 : void KSyncSockTcp::AsyncReceive(mutable_buffers_1 buf, HandlerCb cb) {
     116             :     //Data would be read from ksync tcp session
     117             :     //hence no socket operation would be required
     118           0 : }
     119             : 
     120           0 : void KSyncSockTcp::Receive(mutable_buffers_1 buf) {
     121           0 :     uint32_t bytes_read = 0;
     122           0 :     boost::system::error_code ec;
     123           0 :     const struct nlmsghdr *nlh = NULL;
     124             : 
     125             :     //Create a buffer to read netlink header first
     126             :     mutable_buffers_1 netlink_header(buffer_cast<void *>(buf),
     127           0 :                                      sizeof(struct nlmsghdr));
     128             : 
     129           0 :     bool blocking_socket = session_->socket()->non_blocking();
     130           0 :     session_->socket()->non_blocking(false, ec);
     131           0 :     while (bytes_read < sizeof(struct nlmsghdr)) {
     132             :         mutable_buffers_1 buffer =
     133           0 :             static_cast<mutable_buffers_1>(netlink_header + bytes_read);
     134           0 :         bytes_read += session_->socket()->receive(buffer, 0, ec);
     135           0 :         if (ec.failed()) {
     136           0 :             assert(0);
     137             :         }
     138             :         //Data read is lesser than netlink header
     139             :         //continue reading
     140           0 :         if (bytes_read == sizeof(struct nlmsghdr)) {
     141           0 :             nlh =  buffer_cast<struct nlmsghdr *>(buf);
     142             :         }
     143             :     }
     144             : 
     145           0 :     if (nlh->nlmsg_type == NLMSG_ERROR) {
     146           0 :         LOG(ERROR, "Netlink error for seqno " << nlh->nlmsg_seq
     147             :                 << " len " << nlh->nlmsg_len);
     148           0 :         assert(0);
     149             :     }
     150             : 
     151           0 :     bytes_read = 0;
     152           0 :     uint32_t payload_size = nlh->nlmsg_len - sizeof(struct nlmsghdr);
     153             :     //Read data
     154           0 :     mutable_buffers_1 data(buffer_cast<void *>(buf + sizeof(struct nlmsghdr)),
     155           0 :                            payload_size);
     156             : 
     157           0 :     while (bytes_read < payload_size) {
     158             :         mutable_buffers_1 buffer =
     159           0 :             static_cast<mutable_buffers_1>(data + bytes_read);
     160           0 :         bytes_read += session_->socket()->receive(buffer, 0, ec);
     161           0 :         if (ec.failed()) {
     162           0 :             assert(0);
     163             :         }
     164             :     }
     165           0 :     session_->socket()->non_blocking(blocking_socket, ec);
     166           0 : }
     167             : 
     168           0 : bool KSyncSockTcp::ReceiveMsg(const u_int8_t *msg, size_t size) {
     169           0 :     AgentSandeshContext *ctxt = KSyncSock::GetAgentSandeshContext(0);
     170           0 :     ctxt->SetErrno(0);
     171           0 :     ProcessDataInline((char *) msg);
     172           0 :     return true;
     173             : }
     174             : 
     175           0 : bool KSyncSockTcp::Run() {
     176           0 :     AgentSandeshContext *ctxt = KSyncSock::GetAgentSandeshContext(0);
     177           0 :     int fd = tcp_socket_->native_handle();
     178             : 
     179             :     while (1) {
     180           0 :         char *bufp = rx_buff_;
     181           0 :         struct nlmsghdr *nlh = NULL;
     182             :         struct nlmsghdr tnlh;
     183           0 :         int offset = 0;
     184           0 :         int bytes_transferred = 0;
     185             : 
     186           0 :         bytes_transferred = recv(fd, rx_buff_, kBufLen, 0);
     187           0 :         if (bytes_transferred <= 0) {
     188           0 :              LOG(ERROR, "Connection to dpdk-vrouter lost.");
     189           0 :              sleep(10);
     190           0 :              exit(EXIT_FAILURE);
     191             :         }
     192             : 
     193           0 :         if (remain_ != 0) {
     194           0 :             if (remain_ < sizeof(struct nlmsghdr)) {
     195           0 :                 memcpy((char *)&tnlh, rx_buff_rem_, remain_);
     196           0 :                 memcpy(((char *)&tnlh) + remain_, rx_buff_,
     197           0 :                         (sizeof(struct nlmsghdr) - remain_));
     198           0 :                 nlh =  &tnlh;
     199             :             } else {
     200           0 :                 nlh =  (struct nlmsghdr *)rx_buff_rem_;
     201             :             }
     202             : 
     203           0 :             if (remain_ > nlh->nlmsg_len)
     204           0 :                 assert(0);
     205             : 
     206           0 :             memcpy(rx_buff_rem_+remain_, rx_buff_, nlh->nlmsg_len - remain_);
     207           0 :             bufp += (nlh->nlmsg_len - remain_);
     208           0 :             ctxt->SetErrno(0);
     209           0 :             ProcessDataInline(rx_buff_rem_);
     210           0 :             offset = nlh->nlmsg_len - remain_;
     211             :         }
     212             : 
     213           0 :         while (offset < bytes_transferred) {
     214           0 :             if ((unsigned int)(bytes_transferred - offset) >= (sizeof(struct nlmsghdr))) {
     215           0 :                 nlh =  (struct nlmsghdr *)(rx_buff_ + offset);
     216           0 :                 if ((unsigned int)(bytes_transferred - offset) >= nlh->nlmsg_len) {
     217           0 :                     ctxt->SetErrno(0);
     218           0 :                     ProcessDataInline(rx_buff_ + offset);
     219           0 :                     offset += nlh->nlmsg_len;
     220             :                 } else {
     221           0 :                     break;
     222             :                 }
     223             :             } else {
     224           0 :                 break;
     225             :             }
     226             :         }
     227             : 
     228           0 :         remain_ = bytes_transferred - offset;
     229           0 :         if (remain_) {
     230           0 :             memcpy(rx_buff_rem_, rx_buff_ + offset, bytes_transferred - offset);
     231             :         }
     232           0 :     }
     233             : 
     234             :     return true;
     235             : }
     236             : 
     237             : class KSyncSockTcpReadTask : public Task {
     238             : public:
     239           0 :     KSyncSockTcpReadTask(TaskScheduler *scheduler, KSyncSockTcp *sock) :
     240           0 :         Task(scheduler->GetTaskId("Ksync::KSyncSockTcpRead"), 0), sock_(sock) {
     241           0 :     }
     242           0 :     ~KSyncSockTcpReadTask() {
     243           0 :     }
     244             : 
     245           0 :     bool Run() {
     246           0 :         sock_->Run();
     247           0 :         return true;
     248             :     }
     249           0 :     std::string Description() const { return "KSyncSockTcpRead"; }
     250             : private:
     251             :     KSyncSockTcp *sock_;
     252             : 
     253             : };
     254             : 
     255           0 : void KSyncSockTcp::AsyncReadStart() {
     256             :     static int started = 0;
     257           0 :     boost::system::error_code ec;
     258             : 
     259           0 :     if (!started) {
     260           0 :         TaskScheduler *scheduler = TaskScheduler::GetInstance();
     261           0 :         KSyncSockTcpReadTask *task = new KSyncSockTcpReadTask(scheduler, this);
     262           0 :         tcp_socket_->non_blocking(false, ec);
     263           0 :         scheduler->Enqueue(task);
     264           0 :         started = 1;
     265             :     }
     266           0 : }
     267             : 
     268           0 : void KSyncSockTcp::OnSessionEvent(TcpSession *session,
     269             :                                   TcpSession::Event event) {
     270           0 :     switch (event) {
     271           0 :     case TcpSession::CONNECT_FAILED:
     272             :         //Retry
     273           0 :         Connect(session_, server_ep_);
     274           0 :         break;
     275           0 :     case TcpSession::CLOSE:
     276           0 :         LOG(ERROR, "Connection to dpdk-vrouter lost.");
     277           0 :         sleep(10);
     278           0 :         exit(EXIT_FAILURE);
     279             :         break;
     280           0 :     case TcpSession::CONNECT_COMPLETE:
     281           0 :         tcp_socket_ = session_->socket();
     282           0 :         connect_complete_ = true;
     283           0 :         session_->SetTcpNoDelay();
     284           0 :         session_->SetTcpSendBufSize(max_bulk_buf_size_*16);
     285           0 :         session_->SetTcpRecvBufSize(max_bulk_buf_size_*16);
     286           0 :     default:
     287           0 :         break;
     288             :     }
     289           0 : }
     290             : 
     291             : /////////////////////////////////////////////////////////////////////////////
     292             : // KSyncSockTcpSession routines
     293             : /////////////////////////////////////////////////////////////////////////////
     294           0 : KSyncSockTcpSession::KSyncSockTcpSession(TcpServer *server, Socket *sock,
     295           0 :     bool async_ready) : TcpSession(server, sock, async_ready) {
     296           0 :     KSyncSockTcp *tcp_ptr = static_cast<KSyncSockTcp *>(server);
     297           0 :     reader_ = new KSyncSockTcpSessionReader(this,
     298           0 :                        boost::bind(&KSyncSockTcp::ReceiveMsg, tcp_ptr, _1, _2));
     299           0 : }
     300             : 
     301           0 : KSyncSockTcpSession::~KSyncSockTcpSession() {
     302           0 :     if (reader_) {
     303           0 :         delete reader_;
     304             :     }
     305           0 : }
     306             : 
     307           0 : void KSyncSockTcpSession::OnRead(Buffer buffer) {
     308           0 :     reader_->OnRead(buffer);
     309           0 : }
     310             : 
     311           0 : KSyncSockTcpSessionReader::KSyncSockTcpSessionReader(
     312           0 :     TcpSession *session, ReceiveCallback callback) :
     313           0 :     TcpMessageReader(session, callback) {
     314           0 : }
     315             : 
     316           0 : int KSyncSockTcpSessionReader::MsgLength(Buffer buffer, int offset) {
     317           0 :     size_t size = TcpSession::BufferSize(buffer);
     318           0 :     int remain = size - offset;
     319           0 :     if (remain < GetHeaderLenSize()) {
     320           0 :         return -1;
     321             :     }
     322             : 
     323             :     //Byte ordering?
     324             :     const struct nlmsghdr *nlh =
     325           0 :         (const struct nlmsghdr *)(TcpSession::BufferData(buffer) + offset);
     326           0 :     return nlh->nlmsg_len;
     327             : }

Generated by: LCOV version 1.14