LCOV - code coverage report
Current view: top level - vnsw/agent/services - icmp_error_handler.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 84 0.0 %
Date: 2026-08-03 02:19:58 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : #include <stdint.h>
       5             : #include "base/os.h"
       6             : #include <vr_defs.h>
       7             : #include <cmn/agent_cmn.h>
       8             : #include <oper/interface_common.h>
       9             : #include <oper/vn.h>
      10             : 
      11             : #include <pkt/pkt_init.h>
      12             : #include <pkt/flow_table.h>
      13             : #include <services/icmp_error_proto.h>
      14             : #include <services/icmp_error_handler.h>
      15             : 
      16           0 : IcmpErrorHandler::IcmpErrorHandler(Agent *agent, IcmpErrorProto *proto,
      17             :                                    boost::shared_ptr<PktInfo> info,
      18           0 :                                    boost::asio::io_context *io) :
      19           0 :     ProtoHandler(agent, info, *io), proto_(proto) {
      20           0 : }
      21             : 
      22           0 : IcmpErrorHandler::~IcmpErrorHandler() {
      23           0 : }
      24             : 
      25           0 : bool IcmpErrorHandler::ValidatePacket() {
      26           0 :     if (pkt_info_->len < (sizeof(struct ether_header) + sizeof(struct ip)))
      27           0 :         return false;
      28           0 :     return true;
      29             : }
      30             : 
      31           0 : bool IcmpErrorHandler::Run() {
      32           0 :     if (ValidatePacket() == false) {
      33           0 :         proto_->increment_drops();
      34           0 :         return true;
      35             :     }
      36             : 
      37           0 :     VmInterface *vm_itf = dynamic_cast<VmInterface *>
      38           0 :         (agent()->interface_table()->FindInterface(GetInterfaceIndex()));
      39           0 :     if (vm_itf == NULL || vm_itf->layer3_forwarding() == false ||
      40           0 :         vm_itf->vn() == NULL) {
      41           0 :         proto_->increment_interface_errors();
      42           0 :         return true;
      43             :     }
      44             : 
      45           0 :     return SendIcmpError(vm_itf);
      46             : }
      47             : 
      48             : // Generate ICMP error
      49           0 : bool IcmpErrorHandler::SendIcmpError(VmInterface *intf) {
      50             :     char data[ICMP_PAYLOAD_LEN];
      51           0 :     uint16_t data_len = ntohs(pkt_info_->ip->ip_len);
      52           0 :     if (data_len > ICMP_PAYLOAD_LEN)
      53           0 :         data_len = ICMP_PAYLOAD_LEN;
      54           0 :     memcpy(data, pkt_info_->ip, data_len);
      55             : 
      56           0 :     uint32_t src_ip = 0;
      57           0 :     FlowKey key;
      58           0 :     bool is_nat_flow = false;
      59             : 
      60           0 :     if (pkt_info_->agent_hdr.flow_index == (uint32_t)-1) {
      61             :         // flow index is -1 for 255.255.255.255
      62           0 :         if (pkt_info_->ip_daddr.to_v4().to_ulong() != 0xFFFFFFFF) {
      63           0 :             proto_->increment_invalid_flow_index();
      64           0 :             return true;
      65             :         }
      66           0 :         src_ip = pkt_info_->ip_saddr.to_v4().to_ulong();
      67             :     } else {
      68           0 :         if (proto_->FlowIndexToKey(pkt_info_->agent_hdr.flow_index, &key, &is_nat_flow)
      69           0 :             == false ||
      70           0 :             key.family != Address::INET ||
      71           0 :             ((!is_nat_flow) &&
      72           0 :              (key.src_addr != pkt_info_->ip_saddr ||
      73           0 :               key.dst_addr != pkt_info_->ip_daddr ||
      74           0 :               key.protocol != pkt_info_->ip_proto ||
      75           0 :               key.src_port != pkt_info_->sport ||
      76           0 :               key.dst_port != pkt_info_->dport))) {
      77           0 :             proto_->increment_invalid_flow_index();
      78           0 :             return true;
      79             :         }
      80             : 
      81           0 :         src_ip = key.src_addr.to_v4().to_ulong();
      82             :     }
      83             : 
      84             :     // Get IPAM to find default gateway
      85           0 :     const VnIpam *ipam = intf->vn()->GetIpam(Ip4Address(src_ip));
      86           0 :     if (ipam == NULL || ipam->default_gw.is_v4() == false) {
      87           0 :         proto_->increment_interface_errors();
      88           0 :         return true;
      89             :     }
      90             : 
      91             :     // Retain the agent-header before ethernet header
      92           0 :     uint16_t len = (char *)pkt_info_->eth - (char *)pkt_info_->pkt;
      93           0 :     uint16_t buf_len = pkt_info_->max_pkt_len;
      94             : 
      95             :     // Form ICMP Packet with following
      96             :     // EthHdr - IP Header - ICMP Header - User IP Packet(max 128 bytes)
      97           0 :     char *ptr = (char *)pkt_info_->pkt;
      98           0 :     len += EthHdr(ptr + len, buf_len - len,
      99             :                   agent()->vhost_interface()->mac(),
     100           0 :                   MacAddress(pkt_info_->eth->ether_shost),
     101           0 :                   ETHERTYPE_IP, intf->tx_vlan_id());
     102             : 
     103           0 :     uint16_t icmp_len = ICMP_UNREACH_HDR_LEN;
     104           0 :     uint16_t ip_len = sizeof(struct ip) + icmp_len + data_len;
     105           0 :     len += IpHdr(ptr + len, buf_len - len, ip_len,
     106           0 :             htonl(ipam->default_gw.to_v4().to_ulong()),
     107             :             htonl(src_ip), IPPROTO_ICMP, DEFAULT_IP_ID, DEFAULT_IP_TTL);
     108             : 
     109           0 :     char *icmp = ptr + len;
     110           0 :     len += IcmpHdr(ptr + len, buf_len - len, ICMP_UNREACH,
     111           0 :                    ICMP_UNREACH_NEEDFRAG, 0, pkt_info_->agent_hdr.mtu);
     112             : 
     113           0 :     if (pkt_info_->agent_hdr.flow_index != (uint32_t)-1) {
     114             :         // Its possible that user payload has gone thru NAT processing already.
     115             :         // Restore the original fields from flow_key
     116           0 :         struct ip *ip = (struct ip *)data;
     117           0 :         uint16_t ip_hlen = ip->ip_hl * 4;
     118             : 
     119           0 :         ip->ip_src.s_addr = htonl(key.src_addr.to_v4().to_ulong());
     120           0 :         ip->ip_dst.s_addr = htonl(key.dst_addr.to_v4().to_ulong());
     121           0 :         ip->ip_sum = 0;
     122           0 :         ip->ip_sum = Csum((uint16_t *)data, ip_hlen, 0);
     123           0 :         if (ip->ip_p == IPPROTO_UDP) {
     124           0 :             udphdr *udp = (udphdr *)(data + ip_hlen);
     125           0 :             udp->uh_sport = ntohs(key.src_port);
     126           0 :             udp->uh_dport = ntohs(key.dst_port);
     127           0 :         } else if (ip->ip_p == IPPROTO_TCP) {
     128           0 :             tcphdr *tcp = (tcphdr *)(data + ip_hlen);
     129           0 :             tcp->th_sport = ntohs(key.src_port);
     130           0 :             tcp->th_dport = ntohs(key.dst_port);
     131             :         }
     132             :     }
     133           0 :     memcpy(ptr + len, data, data_len);
     134           0 :     len += data_len;
     135           0 :     IcmpChecksum(icmp, icmp_len + data_len);
     136           0 :     pkt_info_->set_len(len);
     137             : 
     138           0 :     Send(GetInterfaceIndex(), pkt_info_->vrf, AgentHdr::TX_SWITCH,
     139             :          PktHandler::ICMP);
     140           0 :     return true;
     141             : }

Generated by: LCOV version 1.14