ICMP protocol implementation issues

Dear community,

I am adding ICMP protocol to the existing code. The code was working fine before ICMP implementation. Below is given the code with ICMP implementation:

/* -*- P4_17 -*- */
#include <core.p4>
#include <v1model.p4>

const bit<16> TYPE_IPV4 = 0x800;
const bit<8> UDP_PROTOCOL = 0x11;
const bit<8> TCP_PROTOCOL = 0x06;
const bit<16> ETHERTYPE_ARP  = 0x0806;
const bit<8>  IPPROTO_ICMP   = 0x01;

/*************************************************************************
*********************** H E A D E R S  ***********************************
*************************************************************************/

typedef bit<9>  egressSpec_t;
typedef bit<48> macAddr_t;
typedef bit<32> ip4Addr_t;

header ethernet_t {
    macAddr_t dstAddr;
    macAddr_t srcAddr;
    bit<16>   etherType;
}

header ipv4_t {
    bit<4>    version;
    bit<4>    ihl;
    bit<8>    diffserv;
    bit<16>   totalLen;
    bit<16>   identification;
    bit<3>    flags;
    bit<13>   fragOffset;
    bit<8>    ttl;
    bit<8>    protocol;
    bit<16>   hdrChecksum;
    ip4Addr_t srcAddr;
    ip4Addr_t dstAddr;
}

const bit<16> ARP_HTYPE_ETHERNET = 0x0001;
const bit<16> ARP_PTYPE_IPV4     = 0x0800;
const bit<8>  ARP_HLEN_ETHERNET  = 6;
const bit<8>  ARP_PLEN_IPV4      = 4;
const bit<16> ARP_OPER_REQUEST   = 1;
const bit<16> ARP_OPER_REPLY     = 2;

header arp_t {
    bit<16> hrd; // Hardware Type
    bit<16> pro; // Protocol Type
    bit<8> hln; // Hardware Address Length
    bit<8> pln; // Protocol Address Length
    bit<16> op;  // Opcode
    macAddr_t sha; // Sender Hardware Address
    ip4Addr_t spa; // Sender Protocol Address
    macAddr_t tha; // Target Hardware Address
    ip4Addr_t tpa; // Target Protocol Address
}

const bit<8> ICMP_ECHO_REQUEST = 8;
const bit<8> ICMP_ECHO_REPLY   = 0;

header icmp_t {
    bit<8>  type;
    bit<8>  code;
    bit<16> checksum;
}

header udp_t {
    bit<16> srcPort;
    bit<16> dstPort;
    bit<16> length_;
    bit<16> checksum;
}

header tcp_t {
    bit<16> srcPort;
    bit<16> dstPort;
    bit<32> seqNo;
    bit<32> ackNo;
    bit<4>  dataOffset;
    bit<3>  res;
    bit<3>  ecn;
    bit<6>  ctrl;
    bit<16> window;
    bit<16> checksum;
    bit<16> urgentPtr;
}


struct metadata {
    ip4Addr_t dst_ipv4;
    macAddr_t  mac_da;
    macAddr_t  mac_sa;
    egressSpec_t egress_port;
    macAddr_t  my_mac;

    /* empty */
}

header metadata_t {
    bit<32> enq_timestamp;
    bit<32> enq_qdepth;
    bit<32> deq_timedelta;
    bit<32> deq_qdepth;
}


struct headers {
    ethernet_t   ethernet;
    arp_t         arp;
    ipv4_t       ipv4;
    udp_t        udp;
    tcp_t        tcp;
    icmp_t        icmp;
    metadata_t   my_meta;
}

/*************************************************************************
*********************** P A R S E R  ***********************************
*************************************************************************/

parser MyParser(packet_in packet,
                out headers hdr,
                inout metadata meta,
                inout standard_metadata_t standard_metadata) {

    state start {
        transition parse_ethernet;
    }

    state parse_ethernet {
        packet.extract(hdr.ethernet);
        transition select(hdr.ethernet.etherType) {
            TYPE_IPV4: parse_ipv4;
            ETHERTYPE_ARP  : parse_arp;
            default: accept;
        }
    }

    state parse_ipv4 {
        packet.extract(hdr.ipv4);
        transition select(hdr.ipv4.protocol){
        UDP_PROTOCOL: parse_udp;
        TCP_PROTOCOL: parse_tcp;
        IPPROTO_ICMP : parse_icmp;
        default : accept;
    }

}

state parse_arp {
        packet.extract(hdr.arp);
            transition accept;
    }


 state parse_udp{
         packet.extract(hdr.udp);
         transition accept;
    }

 state parse_tcp{
         packet.extract(hdr.tcp);
         transition accept;
    }

state parse_icmp {
        packet.extract(hdr.icmp);
        transition accept;
    }

}

/*************************************************************************
************   C H E C K S U M    V E R I F I C A T I O N   *************
*************************************************************************/
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
    apply {  }
}


/*************************************************************************
**************  I N G R E S S   P R O C E S S I N G   *******************
*************************************************************************/

control MyIngress(inout headers hdr,
                  inout metadata meta,
                  inout standard_metadata_t standard_metadata) {
    action drop() {
        mark_to_drop(standard_metadata);
    }

    action ipv4_forward(egressSpec_t port) {
        //standard_metadata.egress_spec = port;
        //hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
        //hdr.ethernet.dstAddr = dstAddr;
        standard_metadata.egress_spec = port;
        hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
    }

    action arp_forward2(egressSpec_t port) {
        standard_metadata.egress_spec = port;
    }


    table ipv4_lpm {
        key = {
            hdr.ipv4.dstAddr: exact;
        }
        actions = {
            ipv4_forward;
            drop;
            NoAction;
        }
        size = 1024;
        default_action = NoAction();
    }

    action forward_ipv4() {
        //hdr.ethernet.srcAddr = meta.mac_sa;
        hdr.ipv4.ttl         = hdr.ipv4.ttl - 1;

        standard_metadata.egress_spec = meta.egress_port;
    }

    action icmp_forward2() {
        hdr.ipv4.ttl         = hdr.ipv4.ttl - 1;
        standard_metadata.egress_spec = meta.egress_port;

    }

   table arp_forward {
        key = {
            hdr.arp.tpa: exact;
        }
        actions = {
            arp_forward2;
            NoAction;
        }
        size = 1024;
        default_action = NoAction();
    }

   table icmp_forward {
	key = {
	hdr.icmp.type :  exact;
	}
	actions = {
	icmp_forward2;
	NoAction;
	}
	size = 1024;
	default_action = NoAction();
}

    apply {
        ipv4_lpm.apply();
        //forward.apply();
        if (((hdr.arp.isValid()) && (hdr.arp.op == ARP_OPER_REQUEST || hdr.arp.op == ARP_OPER_REPLY))) { arp_forward.apply(); }
       if (hdr.icmp.isValid()) {icmp_forward.apply();}
    }
}

/*************************************************************************
****************  E G R E S S   P R O C E S S I N G   *******************
*************************************************************************/

struct my_egress_metadata{
    bit<48> enq_timestamp;
    bit<19> enq_depth;
    bit<32> deq_time_delta;
    bit<19> deq_depth;
    bit<8> qid;

}
control MyEgress(inout headers hdr,
                 inout metadata meta,
                 inout standard_metadata_t standard_metadata) {
    apply {
           hdr.my_meta.setValid();
           hdr.my_meta.enq_timestamp = 0xA; //standard_metadata.enq_timestamp;
           hdr.my_meta.enq_qdepth = (bit<32>) 0xB; //standard_metadata.enq_qdepth;
           hdr.my_meta.deq_timedelta = 0xC; //standard_metadata.deq_timedelta;
           hdr.my_meta.deq_qdepth = (bit<32>) 0xD; //standard_metadata.deq_qdepth;
 }
}

/*************************************************************************
*************   C H E C K S U M    C O M P U T A T I O N   **************
*************************************************************************/

control MyComputeChecksum(inout headers  hdr, inout metadata meta) {
     apply {
        update_checksum(
        hdr.ipv4.isValid(),
            { hdr.ipv4.version,
              hdr.ipv4.ihl,
              hdr.ipv4.diffserv,
              hdr.ipv4.totalLen,
              hdr.ipv4.identification,
              hdr.ipv4.flags,
              hdr.ipv4.fragOffset,
              hdr.ipv4.ttl,
              hdr.ipv4.protocol,
              hdr.ipv4.srcAddr,
              hdr.ipv4.dstAddr },
            hdr.ipv4.hdrChecksum,
            HashAlgorithm.csum16);
    }
}

/*************************************************************************
***********************  D E P A R S E R  *******************************
*************************************************************************/

control MyDeparser(packet_out packet, in headers hdr) {
    apply {
        packet.emit(hdr.ethernet);
        packet.emit(hdr.arp);
        packet.emit(hdr.ipv4);
        packet.emit(hdr.udp);
        packet.emit(hdr.tcp);
        packet.emit(hdr.icmp);
        packet.emit(hdr.my_meta);
    }
}

/*************************************************************************
***********************  S W I T C H  *******************************
*************************************************************************/

V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;

As shown in console logs below , whenever I ping the host somehow hdr.icmp.isValid is giving false and throwing the packet to port 0.

[21:12:17.376] [bmv2] [T] [thread 371] [28.0] [cxt 0] arp_pl.p4(264) Condition "hdr.icmp.isValid()" (node_5) is false
[21:12:17.376] [bmv2] [D] [thread 371] [28.0] [cxt 0] Pipeline 'ingress': end
[21:12:17.376] [bmv2] [D] [thread 371] [28.0] [cxt 0] Egress port is 0
[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Pipeline 'egress': start
[21:12:17.376] [bmv2] [T] [thread 372] [28.0] [cxt 0] Applying table 'tbl_arp_pl284'
[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Looking up key:

[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Table 'tbl_arp_pl284': miss
[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Action entry is arp_pl284 -
[21:12:17.376] [bmv2] [T] [thread 372] [28.0] [cxt 0] Action arp_pl284
[21:12:17.376] [bmv2] [T] [thread 372] [28.0] [cxt 0] arp_pl.p4(284) Primitive hdr.my_meta.setValid()
[21:12:17.376] [bmv2] [T] [thread 372] [28.0] [cxt 0] arp_pl.p4(285) Primitive hdr.my_meta.enq_timestamp = 0xA
[21:12:17.376] [bmv2] [T] [thread 372] [28.0] [cxt 0] arp_pl.p4(286) Primitive hdr.my_meta.enq_qdepth = (bit<32>) 0xB
[21:12:17.376] [bmv2] [T] [thread 372] [28.0] [cxt 0] arp_pl.p4(287) Primitive hdr.my_meta.deq_timedelta = 0xC
[21:12:17.376] [bmv2] [T] [thread 372] [28.0] [cxt 0] arp_pl.p4(288) Primitive hdr.my_meta.deq_qdepth = (bit<32>) 0xD
[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Pipeline 'egress': end
[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Deparser 'deparser': start
[21:12:17.376] [bmv2] [T] [thread 372] [28.0] [cxt 0] Skipping checksum 'cksum' update because condition not met
[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Deparsing header 'ethernet'
[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Deparsing header 'arp'
[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Deparsing header 'my_meta'
[21:12:17.376] [bmv2] [D] [thread 372] [28.0] [cxt 0] Deparser 'deparser': end
[21:12:17.376] [bmv2] [D] [thread 376] [28.0] [cxt 0] Transmitting packet of size 72 out of port 0

What may be the issue?

After sending ICMP packets using scapy, I realized that ICMP packets were being sent properly from host3 to host2 and they were received at host2 as well.

16:01:53.489502 IP 192.168.1.5 > 192.168.1.3: ICMP echo reply, id 0, seq 11, length 13

When capturing the packets on host3, I realized that whenever I ping host 2, host 3 is requesting ARP request as shown below :

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens7, link-type EN10MB (Ethernet), capture size 262144 bytes
16:01:53.457264 IP 192.168.1.5 > 192.168.1.3: ICMP echo request, id 0, seq 0, length 13
16:02:03.338886 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:02:04.352181 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:02:05.376187 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:02:06.400250 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:02:07.424185 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:02:08.448178 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:05:22.282568 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:05:23.296181 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:05:24.320181 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:05:25.344252 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:05:26.368185 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28
16:05:27.392189 ARP, Request who-has 192.168.1.3 tell 192.168.1.5, length 28

The real issue wasn’t the ICMP packets but was the ARP packets.

1 Like