LCOV - code coverage report
Current view: top level - vnsw/agent/diag - ping.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 207 0.0 %
Date: 2026-11-09 02:10:49 Functions: 0 12 0.0 %
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             : 
       6             : #include <stdint.h>
       7             : #include "base/os.h"
       8             : #include "vr_defs.h"
       9             : #include "cmn/agent_cmn.h"
      10             : #include "oper/nexthop.h"
      11             : #include "oper/route_common.h"
      12             : #include "oper/mirror_table.h"
      13             : #include "pkt/proto.h"
      14             : #include "pkt/proto_handler.h"
      15             : #include "diag/diag_types.h"
      16             : #include "diag/diag_pkt_handler.h"
      17             : #include "diag/diag.h"
      18             : #include "diag/ping.h"
      19             : 
      20             : using namespace boost::posix_time;
      21             : 
      22           0 : Ping::Ping(const PingReq *ping_req, DiagTable *diag_table):
      23             :     DiagEntry(ping_req->get_source_ip(), ping_req->get_dest_ip(),
      24           0 :               ping_req->get_protocol(), ping_req->get_source_port(),
      25           0 :               ping_req->get_dest_port(), ping_req->get_vrf_name(),
      26           0 :               ping_req->get_interval() * 100, ping_req->get_count(), diag_table),
      27           0 :     data_len_(ping_req->get_packet_size()), context_(ping_req->context()),
      28           0 :     pkt_lost_count_(0) {
      29             : 
      30           0 : }
      31             : 
      32           0 : Ping::~Ping() {
      33           0 : }
      34             : 
      35             : void
      36           0 : Ping::FillAgentHeader(AgentDiagPktData *ad) {
      37           0 :     ad->op_ = htonl(AgentDiagPktData::DIAG_REQUEST);
      38           0 :     ad->key_ = htons(key_);
      39           0 :     ad->seq_no_ = htonl(seq_no_);
      40           0 :     ad->rtt_ = microsec_clock::universal_time();
      41           0 :     memset(ad->data_, 0, sizeof(ad->data_));
      42           0 : }
      43             : 
      44             : DiagPktHandler*
      45           0 : Ping::CreateTcpPkt(Agent *agent) {
      46             :     //Allocate buffer to hold packet
      47           0 :     if (sip_.is_v4()) {
      48           0 :         len_ = KPingTcpHdr + data_len_;
      49             :     } else {
      50           0 :         len_ = KPing6TcpHdr + data_len_;
      51             :     }
      52           0 :     boost::shared_ptr<PktInfo> pkt_info(new PktInfo(agent, len_,
      53           0 :                                                     PktHandler::DIAG, 0));
      54           0 :     uint8_t *msg = pkt_info->packet_buffer()->data();
      55           0 :     memset(msg, 0, len_);
      56             : 
      57             :     AgentDiagPktData *ad;
      58           0 :     if (sip_.is_v4()) {
      59           0 :         ad = (AgentDiagPktData *)(msg + KPingTcpHdr);
      60             :     } else {
      61           0 :         ad = (AgentDiagPktData *)(msg + KPing6TcpHdr);
      62             :     }
      63             : 
      64           0 :     FillAgentHeader(ad);
      65           0 :     DiagPktHandler *pkt_handler = new DiagPktHandler(diag_table_->agent(), pkt_info,
      66           0 :                                    *(diag_table_->agent()->event_manager())->io_service());
      67             : 
      68             :     //Update pointers to ethernet header, ip header and l4 header
      69           0 :     if (sip_.is_v4()) {
      70           0 :         pkt_info->UpdateHeaderPtr();
      71           0 :         pkt_handler->TcpHdr(htonl(sip_.to_v4().to_ulong()), sport_,
      72           0 :                             htonl(dip_.to_v4().to_ulong()), dport_, false, rand(),
      73           0 :                             data_len_ + sizeof(tcphdr));
      74           0 :         pkt_handler->IpHdr(data_len_ + sizeof(tcphdr) + sizeof(struct ip),
      75           0 :                            ntohl(sip_.to_v4().to_ulong()),
      76           0 :                            ntohl(dip_.to_v4().to_ulong()), IPPROTO_TCP,
      77             :                            DEFAULT_IP_ID, DEFAULT_IP_TTL);
      78           0 :         pkt_handler->EthHdr(agent->vhost_interface()->mac(),
      79             :                             agent->vrrp_mac(), ETHERTYPE_IP);
      80             :     }else {
      81           0 :         pkt_info->eth = (struct ether_header *)(pkt_info->pkt);
      82           0 :         pkt_info->ip6 = (struct ip6_hdr *)(pkt_info->eth + 1);
      83           0 :         pkt_info->transp.tcp = (struct tcphdr *)(pkt_info->ip6 + 1);
      84           0 :         pkt_handler->TcpHdr(data_len_ + sizeof(tcphdr),
      85           0 :                             (uint8_t *)sip_.to_v6().to_string().c_str(), sport_,
      86           0 :                             (uint8_t *)dip_.to_v6().to_string().c_str(), dport_,
      87           0 :                             false, rand(), IPPROTO_TCP);
      88           0 :         pkt_handler->Ip6Hdr(pkt_info->ip6,
      89           0 :                             data_len_ + sizeof(tcphdr) + sizeof(struct ip6_hdr),
      90             :                             IPPROTO_TCP, DEFAULT_IP_TTL,
      91           0 :                             sip_.to_v6().to_bytes().data(),
      92           0 :                             dip_.to_v6().to_bytes().data());
      93           0 :         pkt_handler->EthHdr(agent->vhost_interface()->mac(),
      94             :                             agent->vrrp_mac(), ETHERTYPE_IPV6);
      95             :     }
      96             : 
      97           0 :     return pkt_handler;
      98           0 : }
      99             : 
     100             : DiagPktHandler*
     101           0 : Ping::CreateUdpPkt(Agent *agent) {
     102             :     //Allocate buffer to hold packet
     103           0 :     if (sip_.is_v4()) {
     104           0 :         len_ = KPingUdpHdr + data_len_;
     105             :     } else {
     106           0 :         len_ = KPing6UdpHdr + data_len_;
     107             :     }
     108           0 :     boost::shared_ptr<PktInfo> pkt_info(new PktInfo(agent, len_,
     109           0 :                                                     PktHandler::DIAG, 0));
     110           0 :     uint8_t *msg = pkt_info->packet_buffer()->data();
     111           0 :     memset(msg, 0, len_);
     112             : 
     113             :     AgentDiagPktData *ad;
     114           0 :     if (sip_.is_v4()) {
     115           0 :         ad = (AgentDiagPktData *)(msg + KPingUdpHdr);
     116             :     } else {
     117           0 :         ad = (AgentDiagPktData *)(msg + KPing6UdpHdr);
     118             :     }
     119             : 
     120           0 :     FillAgentHeader(ad);
     121             : 
     122           0 :     DiagPktHandler *pkt_handler = new DiagPktHandler(diag_table_->agent(), pkt_info,
     123           0 :                                     *(diag_table_->agent()->event_manager())->io_service());
     124             : 
     125             :     //Update pointers to ethernet header, ip header and l4 header
     126           0 :     if (sip_.is_v4()) {
     127           0 :         pkt_info->UpdateHeaderPtr();
     128           0 :         pkt_handler->UdpHdr(data_len_+ sizeof(udphdr), sip_.to_v4().to_ulong(), sport_,
     129           0 :                             dip_.to_v4().to_ulong(), dport_);
     130           0 :         pkt_handler->IpHdr(data_len_ + sizeof(udphdr) + sizeof(struct ip),
     131           0 :                            ntohl(sip_.to_v4().to_ulong()),
     132           0 :                            ntohl(dip_.to_v4().to_ulong()), IPPROTO_UDP,
     133             :                            DEFAULT_IP_ID, DEFAULT_IP_TTL);
     134           0 :         pkt_handler->EthHdr(agent->vhost_interface()->mac(),
     135             :                             agent->vrrp_mac(), ETHERTYPE_IP);
     136             :     } else {
     137           0 :         pkt_info->eth = (struct ether_header *)(pkt_info->pkt);
     138           0 :         pkt_info->ip6 = (struct ip6_hdr *)(pkt_info->eth + 1);
     139           0 :         pkt_info->transp.udp = (struct udphdr *)(pkt_info->ip6 + 1);
     140           0 :         pkt_handler->UdpHdr(data_len_ + sizeof(udphdr),
     141           0 :                             sip_.to_v6().to_bytes().data(), sport_,
     142           0 :                             dip_.to_v6().to_bytes().data(), dport_,
     143             :                             IPPROTO_UDP);
     144           0 :         pkt_handler->Ip6Hdr(pkt_info->ip6,
     145           0 :                             data_len_ + sizeof(udphdr) + sizeof(struct ip6_hdr),
     146             :                             IPPROTO_UDP, DEFAULT_IP_TTL,
     147           0 :                             sip_.to_v6().to_bytes().data(),
     148           0 :                             dip_.to_v6().to_bytes().data());
     149           0 :         pkt_handler->EthHdr(agent->vhost_interface()->mac(),
     150             :                             agent->vrrp_mac(), ETHERTYPE_IPV6);
     151             :     }
     152           0 :     return pkt_handler;
     153           0 : }
     154             : 
     155           0 : void Ping::SendRequest() {
     156           0 :     Agent *agent = Agent::GetInstance();
     157           0 :     DiagPktHandler *pkt_handler = NULL;
     158             :     //Increment the attempt count
     159           0 :     seq_no_++;
     160           0 :     switch(proto_) {
     161           0 :     case IPPROTO_TCP:
     162           0 :         pkt_handler = CreateTcpPkt(agent);
     163           0 :         break;
     164             : 
     165           0 :     case IPPROTO_UDP:
     166           0 :         pkt_handler = CreateUdpPkt(agent);
     167           0 :         break;
     168             :     }
     169             : 
     170             :     InetUnicastAgentRouteTable *table;
     171           0 :     if (sip_.is_v4()) {
     172           0 :         table = agent->vrf_table()->GetInet4UnicastRouteTable(vrf_name_);
     173             :     } else {
     174           0 :         table = agent->vrf_table()->GetInet6UnicastRouteTable(vrf_name_);
     175             :     }
     176           0 :     AgentRoute *rt = table->FindRoute(sip_);
     177           0 :     if (!rt) {
     178           0 :         delete pkt_handler;
     179           0 :         return;
     180             :     }
     181             : 
     182             :     const NextHop *nh;
     183           0 :     nh = rt->GetActiveNextHop();
     184           0 :     if (!nh || nh->GetType() != NextHop::INTERFACE) {
     185           0 :         delete pkt_handler;
     186           0 :         return;
     187             :     }
     188             : 
     189             :     const InterfaceNH *intf_nh;
     190           0 :     intf_nh = static_cast<const InterfaceNH *>(nh);
     191             : 
     192           0 :     uint32_t intf_id = intf_nh->GetInterface()->id();
     193           0 :     uint32_t vrf_id = diag_table_->agent()->vrf_table()->FindVrfFromName(vrf_name_)->vrf_id();
     194             :     //Send request out
     195           0 :     pkt_handler->SetDiagChkSum();
     196           0 :     pkt_handler->pkt_info()->set_len(len_);
     197           0 :     pkt_handler->Send(intf_id, vrf_id, AgentHdr::TX_ROUTE,
     198             :                       CMD_PARAM_PACKET_CTRL, CMD_PARAM_1_DIAG, PktHandler::DIAG);
     199           0 :     delete pkt_handler;
     200           0 :     return;
     201             : }
     202             : 
     203           0 : void Ping::RequestTimedOut(uint32_t seqno) {
     204           0 :     PingResp *resp = new PingResp();
     205           0 :     pkt_lost_count_++;
     206           0 :     resp->set_resp("Timed Out");
     207           0 :     resp->set_seq_no(seqno);
     208           0 :     resp->set_context(context_);
     209           0 :     resp->set_more(true);
     210           0 :     resp->Response();
     211           0 : }
     212             : 
     213           0 : void time_duration_to_string(time_duration &td, std::string &str) {
     214           0 :     std::ostringstream td_str;
     215             : 
     216           0 :     if (td.minutes()) {
     217           0 :         td_str << td.minutes() << "m " << td.seconds() << "s";
     218           0 :     } else if (td.total_milliseconds()) {
     219           0 :         td_str << td.total_milliseconds() << "ms";
     220           0 :     } else if (td.total_microseconds()) {
     221           0 :         td_str << td.total_microseconds() << "us";
     222             :     } else {
     223           0 :         td_str << td.total_nanoseconds() << "ns";
     224             :     }
     225             : 
     226           0 :     str = td_str.str();
     227           0 : }
     228             : 
     229           0 : void Ping::HandleReply(DiagPktHandler *handler) {
     230             :     //Send reply
     231           0 :     PingResp *resp = new PingResp();
     232           0 :     AgentDiagPktData *ad = (AgentDiagPktData *)handler->GetData();
     233             : 
     234           0 :     resp->set_seq_no(ntohl(ad->seq_no_));
     235             : 
     236             :     //Calculate rtt
     237           0 :     time_duration rtt = microsec_clock::universal_time() - ad->rtt_;
     238           0 :     avg_rtt_ += rtt;
     239           0 :     std::string rtt_str;
     240           0 :     time_duration_to_string(rtt, rtt_str);
     241           0 :     resp->set_rtt(rtt_str);
     242             : 
     243           0 :     resp->set_resp("Success");
     244           0 :     resp->set_context(context_);
     245           0 :     resp->set_more(true);
     246           0 :     resp->Response();
     247           0 : }
     248             : 
     249           0 : void Ping::SendSummary() {
     250           0 :     PingSummaryResp *resp = new PingSummaryResp();
     251             : 
     252           0 :     if (pkt_lost_count_ != GetMaxAttempts()) {
     253             :         //If we had some succesful replies, send in
     254             :         //average rtt for succesful ping requests
     255           0 :         avg_rtt_ = (avg_rtt_ / (seq_no_ - pkt_lost_count_));
     256           0 :         std::string avg_rtt_string;
     257           0 :         time_duration_to_string(avg_rtt_, avg_rtt_string);
     258           0 :         resp->set_average_rtt(avg_rtt_string);
     259           0 :     }
     260             : 
     261           0 :     resp->set_request_sent(seq_no_);
     262           0 :     resp->set_response_received(seq_no_ - pkt_lost_count_);
     263           0 :     uint32_t pkt_loss_percent = (pkt_lost_count_ * 100/seq_no_);
     264           0 :     resp->set_pkt_loss(pkt_loss_percent);
     265           0 :     resp->set_context(context_);
     266           0 :     resp->Response();
     267           0 : }
     268             : 
     269           0 : void PingReq::HandleRequest() const {
     270           0 :     std::string err_str;
     271           0 :     boost::system::error_code ec;
     272           0 :     Ping *ping = NULL;
     273             : 
     274             :     {
     275           0 :     IpAddress sip(IpAddress::from_string(get_source_ip(), ec));
     276           0 :     if (ec.failed()) {
     277           0 :         err_str = "Invalid source IP";
     278           0 :         goto error;
     279             :     }
     280             : 
     281           0 :     IpAddress dip(IpAddress::from_string(get_dest_ip(), ec));
     282           0 :     if (ec.failed()) {
     283           0 :         err_str = "Invalid destination IP";
     284           0 :         goto error;
     285             :     }
     286             : 
     287           0 :     uint8_t proto = get_protocol();
     288           0 :     if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
     289           0 :         err_str = "Invalid protocol. Valid Protocols are TCP and UDP";
     290           0 :         goto error;
     291             :     }
     292             : 
     293           0 :     if (Agent::GetInstance()->vrf_table()->FindVrfFromName(get_vrf_name()) == NULL) {
     294           0 :         err_str = "Invalid VRF";
     295           0 :         goto error;
     296             :     }
     297             : 
     298           0 :     const NextHop *nh = NULL;
     299           0 :     Agent *agent = Agent::GetInstance();
     300             :     InetUnicastAgentRouteTable *table;
     301           0 :     if (sip.is_v4()) {
     302           0 :         table = agent->vrf_table()->GetInet4UnicastRouteTable(get_vrf_name());
     303             :     } else {
     304           0 :         table = agent->vrf_table()->GetInet6UnicastRouteTable(get_vrf_name());
     305             :     }
     306           0 :     AgentRoute *rt = table->FindRoute(sip);
     307           0 :     if (rt) {
     308           0 :         nh = rt->GetActiveNextHop();
     309             :     }
     310           0 :     if (!nh || nh->GetType() != NextHop::INTERFACE) {
     311           0 :         err_str = "VM not present on this server";
     312           0 :         goto error;
     313             :     }
     314             :     }
     315           0 :     ping = new Ping(this, Agent::GetInstance()->diag_table());
     316           0 :     ping->Init();
     317           0 :     return;
     318             : 
     319           0 : error:
     320           0 :     PingErrResp *resp = new PingErrResp;
     321           0 :     resp->set_error_response(err_str);
     322           0 :     resp->set_context(context());
     323           0 :     resp->Response();
     324           0 :     return;
     325           0 : }

Generated by: LCOV version 1.14