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

Generated by: LCOV version 1.14