LCOV - code coverage report
Current view: top level - vnsw/agent/diag - traceroute.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 195 0.0 %
Date: 2026-06-04 02:06:09 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include <stdint.h>
       6             : #include <netinet/udp.h>
       7             : #include <netinet/tcp.h>
       8             : #include <netinet/icmp6.h>
       9             : #include "vr_defs.h"
      10             : #include "cmn/agent_cmn.h"
      11             : #include "oper/nexthop.h"
      12             : #include "oper/route_common.h"
      13             : #include "oper/mirror_table.h"
      14             : #include "pkt/proto.h"
      15             : #include "pkt/proto_handler.h"
      16             : #include "diag/diag_types.h"
      17             : #include "diag/diag_pkt_handler.h"
      18             : #include "diag/diag.h"
      19             : #include "diag/traceroute.h"
      20             : 
      21             : void
      22           0 : TraceRoute::SendSandeshReply(const std::string &address,
      23             :                              const std::string &context,
      24             :                              bool more) {
      25           0 :     TraceRouteResp *resp = new TraceRouteResp();
      26           0 :     resp->set_hop(address);
      27             : 
      28           0 :     resp->set_context(context);
      29           0 :     resp->set_more(more);
      30           0 :     resp->Response();
      31           0 : }
      32             : 
      33           0 : TraceRoute::TraceRoute(const TraceRouteReq *trace_route_req,
      34           0 :                        DiagTable *diag_table) :
      35             :     DiagEntry(trace_route_req->get_source_ip(), trace_route_req->get_dest_ip(),
      36           0 :               trace_route_req->get_protocol(), trace_route_req->get_source_port(),
      37           0 :               trace_route_req->get_dest_port(), trace_route_req->get_vrf_name(),
      38           0 :               trace_route_req->get_interval() * 100,
      39           0 :               trace_route_req->get_max_attempts(), diag_table),
      40           0 :     done_(false), ttl_(2),
      41           0 :     max_ttl_(trace_route_req->get_max_hops()),
      42           0 :     context_(trace_route_req->context()) {
      43           0 : }
      44             : 
      45           0 : TraceRoute::~TraceRoute() {
      46           0 : }
      47             : 
      48           0 : void TraceRoute::FillHeader(AgentDiagPktData *data) {
      49           0 :     data->op_ = htonl(AgentDiagPktData::DIAG_REQUEST);
      50           0 :     data->key_ = htons(key_);
      51           0 :     data->seq_no_ = htonl(seq_no_);
      52           0 :     memset(data->data_, 0, sizeof(data->data_));
      53             :     // data->rtt_ = microsec_clock::universal_time();
      54           0 : }
      55             : 
      56           0 : void TraceRoute::SendRequest() {
      57           0 :     Agent *agent = diag_table_->agent();
      58             : 
      59             :     InetUnicastAgentRouteTable *table;
      60           0 :     if (sip_.is_v4()) {
      61           0 :         table = agent->vrf_table()->GetInet4UnicastRouteTable(vrf_name_);
      62             :     } else {
      63           0 :         table = agent->vrf_table()->GetInet6UnicastRouteTable(vrf_name_);
      64             :     }
      65           0 :     AgentRoute *rt = table->FindRoute(sip_);
      66           0 :     if (!rt) return;
      67             : 
      68           0 :     const NextHop *nh = rt->GetActiveNextHop();
      69           0 :     if (!nh || nh->GetType() != NextHop::INTERFACE) return;
      70             : 
      71             :     const InterfaceNH *intf_nh;
      72           0 :     intf_nh = static_cast<const InterfaceNH *>(nh);
      73             : 
      74           0 :     uint32_t intf_id = intf_nh->GetInterface()->id();
      75           0 :     uint32_t vrf_id = agent->vrf_table()->FindVrfFromName(vrf_name_)->vrf_id();
      76             : 
      77             :     //Allocate buffer to hold packet
      78             :     boost::shared_ptr<PktInfo> pkt_info(new PktInfo(agent, kBufferSize,
      79           0 :                                                     PktHandler::DIAG, 0));
      80           0 :     uint8_t *msg = pkt_info->packet_buffer()->data();
      81           0 :     memset(msg, 0, kBufferSize);
      82             : 
      83             :     DiagPktHandler *pkt_handler =
      84             :         new DiagPktHandler(agent, pkt_info,
      85           0 :                            *(agent->event_manager())->io_service());
      86           0 :     uint16_t len = sizeof(AgentDiagPktData);
      87           0 :     uint8_t *data = NULL;
      88           0 :     if (sip_.is_v4()) {
      89             :     //Update pointers to ethernet header, ip header and l4 header
      90           0 :         pkt_info->UpdateHeaderPtr();
      91           0 :         switch (proto_) {
      92           0 :             case IPPROTO_TCP:
      93           0 :                 len += sizeof(tcphdr);
      94           0 :                 data = (uint8_t *)pkt_handler->pkt_info()->transp.tcp + sizeof(tcphdr);
      95           0 :                 pkt_handler->TcpHdr(htonl(sip_.to_v4().to_ulong()), sport_,
      96           0 :                                     htonl(dip_.to_v4().to_ulong()), dport_,
      97           0 :                                     false, rand(), len);
      98           0 :                 pkt_handler->pkt_info()->transp.tcp->check = 0xffff;
      99           0 :                 break;
     100             : 
     101           0 :             case IPPROTO_UDP:
     102           0 :                 len += sizeof(udphdr);
     103           0 :                 data = (uint8_t *)pkt_handler->pkt_info()->transp.udp + sizeof(udphdr);
     104           0 :                 pkt_handler->UdpHdr(len, sip_.to_v4().to_ulong(), sport_,
     105           0 :                                     dip_.to_v4().to_ulong(), dport_);
     106           0 :                 pkt_handler->pkt_info()->transp.udp->check = 0xffff;
     107           0 :                 break;
     108             : 
     109           0 :             case IPPROTO_ICMP:
     110           0 :                 len += 8;
     111           0 :                 data = (uint8_t *)pkt_handler->pkt_info()->transp.icmp + 8;
     112           0 :                 pkt_handler->pkt_info()->transp.icmp->icmp_type = ICMP_ECHO;
     113           0 :                 pkt_handler->pkt_info()->transp.icmp->icmp_code = 0;
     114           0 :                 pkt_handler->pkt_info()->transp.icmp->icmp_cksum = 0xffff;
     115           0 :                 break;
     116             :         }
     117           0 :         FillHeader((AgentDiagPktData *)data);
     118           0 :         len += sizeof(struct ip);
     119           0 :         pkt_handler->IpHdr(len, ntohl(sip_.to_v4().to_ulong()),
     120           0 :                            ntohl(dip_.to_v4().to_ulong()),
     121           0 :                            proto_, key_, ttl_);
     122           0 :         len += sizeof(ether_header);
     123           0 :         pkt_handler->EthHdr(agent->vhost_interface()->mac(),
     124             :                             agent->vrrp_mac(), ETHERTYPE_IP);
     125             :     } else {
     126           0 :         pkt_info->eth = (struct ether_header *)(pkt_handler->pkt_info()->pkt);
     127           0 :         pkt_info->ip6 = (struct ip6_hdr *)(pkt_info->eth + 1);
     128           0 :         switch (proto_) {
     129           0 :             case IPPROTO_TCP:
     130           0 :                 pkt_info->transp.tcp = (struct tcphdr *)(pkt_info->ip6 + 1);
     131           0 :                 len += sizeof(tcphdr);
     132           0 :                 data = (uint8_t *)pkt_handler->pkt_info()->transp.tcp + sizeof(tcphdr);
     133           0 :                 pkt_handler->TcpHdr(len+sizeof(tcphdr),
     134           0 :                                     sip_.to_v6().to_bytes().data(), sport_,
     135           0 :                                     dip_.to_v6().to_bytes().data(), dport_,
     136           0 :                                     false, rand(), IPPROTO_TCP);
     137           0 :                 pkt_handler->pkt_info()->transp.tcp->check = 0xffff;
     138           0 :                 break;
     139             : 
     140           0 :             case IPPROTO_UDP:
     141           0 :                 pkt_info->transp.udp = (struct udphdr *)(pkt_info->ip6 + 1);
     142           0 :                 len += sizeof(udphdr);
     143           0 :                 data = (uint8_t *)pkt_handler->pkt_info()->transp.udp + sizeof(udphdr);
     144           0 :                 pkt_handler->UdpHdr(len + sizeof(udphdr),
     145           0 :                                     sip_.to_v6().to_bytes().data(), sport_,
     146           0 :                                     dip_.to_v6().to_bytes().data(), dport_,
     147             :                                     IPPROTO_UDP);
     148           0 :                 pkt_handler->pkt_info()->transp.udp->check = 0xffff;
     149           0 :                 break;
     150             : 
     151           0 :             case IPPROTO_ICMPV6:
     152           0 :                 len += 8;
     153           0 :                 data = (uint8_t *)pkt_handler->pkt_info()->transp.icmp + 8;
     154           0 :                 pkt_handler->pkt_info()->transp.icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
     155           0 :                 pkt_handler->pkt_info()->transp.icmp6->icmp6_code = 0;
     156           0 :                 pkt_handler->pkt_info()->transp.icmp6->icmp6_cksum = 0xffff;
     157           0 :                 break;
     158             :         }
     159           0 :         FillHeader((AgentDiagPktData *)data);
     160           0 :         len += sizeof(struct ip6_hdr);
     161           0 :         pkt_handler->Ip6Hdr(pkt_info->ip6,
     162           0 :                             len + sizeof(udphdr) + sizeof(struct ip6_hdr),
     163           0 :                             IPPROTO_UDP, ttl_, sip_.to_v6().to_bytes().data(),
     164           0 :                             dip_.to_v6().to_bytes().data());
     165           0 :         len += sizeof(ether_header);
     166           0 :         pkt_handler->EthHdr(agent->vhost_interface()->mac(),
     167             :                             agent->vrrp_mac(), ETHERTYPE_IPV6);
     168             :     }
     169             :     //Increment the attempt count
     170           0 :     seq_no_++;
     171             : 
     172             :     //Send request out
     173           0 :     pkt_handler->pkt_info()->set_len(len);
     174           0 :     pkt_handler->Send(intf_id, vrf_id, AgentHdr::TX_ROUTE,
     175             :                       CMD_PARAM_PACKET_CTRL, CMD_PARAM_1_DIAG, PktHandler::DIAG);
     176           0 :     delete pkt_handler;
     177           0 :     return;
     178           0 : }
     179             : 
     180             : // if timed out max times for a TTL, reply and increment ttl
     181           0 : void TraceRoute::RequestTimedOut(uint32_t seqno) {
     182           0 :     if (seq_no_ >= GetMaxAttempts()) {
     183           0 :         std::string address;
     184           0 :         for (uint32_t i = 0; i < GetMaxAttempts(); i++)
     185           0 :             address += "* ";
     186             : 
     187           0 :         done_ = ((ttl_ >= max_ttl_) ? true : false);
     188           0 :         SendSandeshReply(address, context_, !done_);
     189           0 :         IncrementTtl();
     190           0 :     }
     191           0 : }
     192             : 
     193             : // Ready to send a response and increment ttl
     194           0 : void TraceRoute::HandleReply(DiagPktHandler *handler) {
     195           0 :     if (ttl_ >= max_ttl_) {
     196           0 :         handler->set_done(true);
     197           0 :         done_ = true;
     198             :     }
     199           0 :     SendSandeshReply(handler->GetAddress(), context_, !handler->IsDone());
     200           0 :     IncrementTtl();
     201           0 : }
     202             : 
     203             : // Reply with local node as the first hop
     204           0 : void TraceRoute::ReplyLocalHop() {
     205           0 :     SendSandeshReply(diag_table_->agent()->router_id().to_string(),
     206           0 :                      context_, true);
     207           0 : }
     208             : 
     209           0 : void TraceRoute::SendSummary() {
     210           0 : }
     211             : 
     212           0 : bool TraceRoute::IsDone() {
     213           0 :     return done_;
     214             : }
     215             : 
     216           0 : void TraceRoute::IncrementTtl() {
     217           0 :     ttl_++;
     218           0 :     seq_no_ = 0;
     219           0 : }
     220             : 
     221           0 : void TraceRouteReq::HandleRequest() const {
     222           0 :     std::string err_str;
     223           0 :     boost::system::error_code ec;
     224           0 :     TraceRoute *trace_route = NULL;
     225             : 
     226             :     {
     227           0 :         IpAddress sip(IpAddress::from_string(get_source_ip(), ec));
     228           0 :         if (ec.failed()) {
     229           0 :             err_str = "Invalid source IP";
     230           0 :             goto error;
     231             :         }
     232             : 
     233           0 :         IpAddress dip(IpAddress::from_string(get_dest_ip(), ec));
     234           0 :         if (ec.failed()) {
     235           0 :             err_str = "Invalid destination IP";
     236           0 :             goto error;
     237             :         }
     238             : 
     239           0 :         uint8_t proto = get_protocol();
     240           0 :         if (proto != IPPROTO_TCP && proto != IPPROTO_UDP && proto != IPPROTO_ICMP) {
     241           0 :             err_str = "Invalid protocol - Supported protocols are TCP, UDP and ICMP";
     242           0 :             goto error;
     243             :         }
     244             : 
     245           0 :         if (Agent::GetInstance()->vrf_table()->FindVrfFromName(get_vrf_name()) == NULL) {
     246           0 :             err_str = "Invalid VRF";
     247           0 :             goto error;
     248             :         }
     249             : 
     250           0 :         const NextHop *nh = NULL;
     251           0 :         Agent *agent = Agent::GetInstance();
     252             :         InetUnicastAgentRouteTable *table;
     253           0 :         if (sip.is_v4()) {
     254           0 :             table = agent->vrf_table()->GetInet4UnicastRouteTable(get_vrf_name());
     255             :         } else {
     256           0 :             table = agent->vrf_table()->GetInet6UnicastRouteTable(get_vrf_name());
     257             :         }
     258           0 :         AgentRoute *rt = table->FindRoute(sip);
     259           0 :         if (rt) {
     260           0 :             nh = rt->GetActiveNextHop();
     261             :         }
     262           0 :         if (!nh || nh->GetType() != NextHop::INTERFACE) {
     263           0 :             err_str = "Source VM is not present in this server";
     264           0 :             goto error;
     265             :         }
     266             : 
     267           0 :         rt = table->FindRoute(dip);
     268           0 :         if (rt) {
     269           0 :             nh = rt->GetActiveNextHop();
     270           0 :             if (nh && nh->GetType() == NextHop::INTERFACE) {
     271             :                 // Dest VM is also local
     272           0 :                 TraceRoute::SendSandeshReply(agent->router_id().to_string(),
     273           0 :                                              context(), false);
     274           0 :                 return;
     275             :             }
     276             :         }
     277             :     }
     278             : 
     279           0 :     trace_route = new TraceRoute(this, Agent::GetInstance()->diag_table());
     280           0 :     trace_route->ReplyLocalHop();
     281           0 :     trace_route->Init();
     282           0 :     return;
     283             : 
     284           0 : error:
     285           0 :     TraceRouteErrResp *resp = new TraceRouteErrResp;
     286           0 :     resp->set_error_response(err_str);
     287           0 :     resp->set_context(context());
     288           0 :     resp->Response();
     289           0 :     return;
     290           0 : }

Generated by: LCOV version 1.14