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

Generated by: LCOV version 1.14