p4lang / behavioral-model

The reference P4 software switch
Apache License 2.0
532 stars 327 forks source link

Failure whilst using the clone primitive #1177

Closed TLDart closed 1 year ago

TLDart commented 1 year ago

Hello, I am trying to implement a simple example of packet cloning but the clone primitive does not seem to work.

Regarding my testing environment:

Checking the log file (which I am going to only present the useful parts), after using the clone primitive, the cloning operation is started, but the packet never reaches the switch (furthermore, no [.1 ] is ever listed.

When compared to i2e log example, after the line "Cloning packet at ingress", a new packet is processed, numbered .1 , which does not happen in my logs either.

I was wondering if I am doing something wrong, if there is a problem on my end, or if it is just a bug.

Best regards, Duarte

Files

Topology

{
    "hosts": {
        "h1": {"ip": "10.0.1.1/24", "mac": "08:00:00:00:01:11",
               "commands":["route add default gw 10.0.1.10 dev eth0",
                           "arp -i eth0 -s 10.0.1.10 08:00:00:00:01:00"]},
        "h2": {"ip": "10.0.2.2/24", "mac": "08:00:00:00:02:22",
               "commands":["route add default gw 10.0.2.20 dev eth0",
                           "arp -i eth0 -s 10.0.2.20 08:00:00:00:02:00"]},
        "h3": {"ip": "10.0.3.3/24", "mac": "08:00:00:00:03:33",
               "commands":["route add default gw 10.0.3.30 dev eth0",
                           "arp -i eth0 -s 10.0.3.30 08:00:00:00:03:00"]}
    },
    "switches": {
        "s1": { "runtime_json" : "triangle-topo/s1-runtime.json", "program": "build/basic.json" },
        "s2": { "runtime_json" : "triangle-topo/s2-runtime.json", "program": "build/clone.json" },
        "s3": { "runtime_json" : "triangle-topo/s3-runtime.json", "program": "build/basic.json" }
    },
    "links": [
        ["h1", "s1-p1"], ["s1-p2", "s2-p2"], ["s1-p3", "s3-p2"],
        ["s3-p3", "s2-p3"], ["h2", "s2-p1"], ["h3", "s3-p1"]
    ]
}

clone.p4

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

const bit<16> TYPE_IPV4 = 0x800;

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

const bit<32> BMV2_V1MODEL_INSTANCE_TYPE_NORMAL        = 0;
const bit<32> BMV2_V1MODEL_INSTANCE_TYPE_INGRESS_CLONE = 1;
const bit<32> BMV2_V1MODEL_INSTANCE_TYPE_EGRESS_CLONE  = 2;
const bit<32> BMV2_V1MODEL_INSTANCE_TYPE_COALESCED     = 3;
const bit<32> BMV2_V1MODEL_INSTANCE_TYPE_RECIRC        = 4;
const bit<32> BMV2_V1MODEL_INSTANCE_TYPE_REPLICATION   = 5;
const bit<32> BMV2_V1MODEL_INSTANCE_TYPE_RESUBMIT      = 6;

#define IS_RESUBMITTED(std_meta) (std_meta.instance_type == BMV2_V1MODEL_INSTANCE_TYPE_RESUBMIT)
#define IS_RECIRCULATED(std_meta) (std_meta.instance_type == BMV2_V1MODEL_INSTANCE_TYPE_RECIRC)
#define IS_I2E_CLONE(std_meta) (std_meta.instance_type == BMV2_V1MODEL_INSTANCE_TYPE_INGRESS_CLONE)
#define IS_E2E_CLONE(std_meta) (std_meta.instance_type == BMV2_V1MODEL_INSTANCE_TYPE_EGRESS_CLONE)
#define IS_REPLICATED(std_meta) (std_meta.instance_type == BMV2_V1MODEL_INSTANCE_TYPE_REPLICATION)

const bit<32> I2E_CLONE_SESSION_ID = 5;
const bit<32> E2E_CLONE_SESSION_ID = 11;

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;
}

struct metadata {
    /* empty */
    @field_list(0)
    bit<8> test;
}

struct headers {
    ethernet_t   ethernet;
    ipv4_t       ipv4;
}

/*************************************************************************
*********************** 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;
            default: accept;
        }
    }

    state parse_ipv4 {
        packet.extract(hdr.ipv4);
        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(macAddr_t dstAddr, egressSpec_t port) {
        standard_metadata.egress_spec = port;
        hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
        hdr.ethernet.dstAddr = dstAddr;
        hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
    }

     action clone_packet() {
        const bit<32> CLONE_ID = 42;
        clone_preserving_field_list(CloneType.I2E, CLONE_ID,0);
    }

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

    apply {
        if (hdr.ipv4.isValid()) {
            clone_packet();
            ipv4_lpm.apply();

        }
    }
}

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

control MyEgress(inout headers hdr,
                 inout metadata meta,
                 inout standard_metadata_t standard_metadata) {

        action ipv4_forward_change(ip4Addr_t dstIP, macAddr_t dstAddr, egressSpec_t port) {
            standard_metadata.egress_spec = port;
            hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
            hdr.ethernet.dstAddr = dstAddr;
            hdr.ipv4.dstAddr = dstIP;
            hdr.ipv4.ttl = hdr.ipv4.ttl - 1;
        }

        table dbg_table {
        key = {
            standard_metadata.ingress_port : exact;
            standard_metadata.egress_spec : exact;
            standard_metadata.egress_port : exact;
            standard_metadata.instance_type : exact;
            standard_metadata.packet_length : exact;
            standard_metadata.enq_timestamp : exact;
            standard_metadata.enq_qdepth : exact;
            standard_metadata.deq_timedelta : exact;
            standard_metadata.deq_qdepth : exact;
            standard_metadata.ingress_global_timestamp : exact;
            standard_metadata.egress_global_timestamp : exact;
            standard_metadata.mcast_grp : exact;
            standard_metadata.egress_rid : exact;
            standard_metadata.checksum_error : exact;
        }
        actions = { NoAction; }
        const default_action = NoAction();
    }

    table ipv4_deviate {
        key = {
            hdr.ipv4.dstAddr: lpm;
        }
        actions = {
            ipv4_forward_change;
            NoAction;
        }
        size = 1024;
        default_action = NoAction();
    }

    apply {
        dbg_table.apply();
         if (IS_I2E_CLONE(standard_metadata)) { ipv4_deviate.apply();}
     }
}

/*************************************************************************
*************   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.ipv4);
    }
}

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

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

Logs (for switch 2)

[17:11:43.308] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Processing packet received on port 1
[17:11:43.308] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Parser 'parser': start
[17:11:43.308] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Parser 'parser' entering state 'start'
[17:11:43.308] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Extracting header 'ethernet'
[17:11:43.308] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Parser state 'start': key is 0800
[17:11:43.308] [bmv2] [T] [thread 7604] [30.0] [cxt 0] Bytes parsed: 14
[17:11:43.308] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Parser 'parser' entering state 'parse_ipv4'
[17:11:43.308] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Extracting header 'ipv4'
[17:11:43.308] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Parser state 'parse_ipv4' has no switch, going to default next state
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] Bytes parsed: 34
[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Parser 'parser': end
[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Pipeline 'ingress': start
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] clone.p4(140) Condition "hdr.ipv4.isValid()" (node_2) is true
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] Applying table 'tbl_clone_packet'
[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Looking up key:

[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Table 'tbl_clone_packet': miss
[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Action entry is MyIngress.clone_packet - 
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] Action MyIngress.clone_packet
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] clone.p4(122) Primitive clone_preserving_field_list(CloneType.I2E, CLONE_ID, 0)
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] Applying table 'MyIngress.ipv4_lpm'
[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Looking up key:
* hdr.ipv4.dstAddr    : 0a000101

[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Table 'MyIngress.ipv4_lpm': hit with handle 0
[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Dumping entry 0
Match key:
* hdr.ipv4.dstAddr    : LPM       0a000101/32
Action entry: MyIngress.ipv4_forward - 80000000100,2,

[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Action entry is MyIngress.ipv4_forward - 80000000100,2,
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] Action MyIngress.ipv4_forward
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] clone.p4(114) Primitive standard_metadata.egress_spec = port
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] clone.p4(115) Primitive hdr.ethernet.srcAddr = hdr.ethernet.dstAddr
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] clone.p4(116) Primitive hdr.ethernet.dstAddr = dstAddr
[17:11:43.309] [bmv2] [T] [thread 7604] [30.0] [cxt 0] clone.p4(117) Primitive hdr.ipv4.ttl = hdr.ipv4.ttl - 1
[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Pipeline 'ingress': end
[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Cloning packet at ingress
[17:11:43.309] [bmv2] [D] [thread 7604] [30.0] [cxt 0] Egress port is 2
[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Pipeline 'egress': start
[17:11:43.309] [bmv2] [T] [thread 7607] [30.0] [cxt 0] Applying table 'MyEgress.dbg_table'
[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Looking up key:
* standard_metadata.ingress_port            : 0001
* standard_metadata.egress_spec             : 0000
* standard_metadata.egress_port             : 0002
* standard_metadata.instance_type           : 00000000
* standard_metadata.packet_length           : 0000003a
* standard_metadata.enq_timestamp           : 01337365
* standard_metadata.enq_qdepth              : 000000
* standard_metadata.deq_timedelta           : 00000012
* standard_metadata.deq_qdepth              : 000000
* standard_metadata.ingress_global_timestamp: 000001337295
* standard_metadata.egress_global_timestamp : 000001337376
* standard_metadata.mcast_grp               : 0000
* standard_metadata.egress_rid              : 0000
* standard_metadata.checksum_error          : 00

[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Table 'MyEgress.dbg_table': miss
[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Action entry is NoAction - 
[17:11:43.309] [bmv2] [T] [thread 7607] [30.0] [cxt 0] Action NoAction
[17:11:43.309] [bmv2] [T] [thread 7607] [30.0] [cxt 0] clone.p4(200) Condition "standard_metadata.instance_type == BMV2_V1MODEL_INSTANCE_TYPE_INGRESS_CLONE" (node_8) is false
[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Pipeline 'egress': end
[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Deparser 'deparser': start
[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Updating checksum 'cksum'
[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Deparsing header 'ethernet'
[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Deparsing header 'ipv4'
[17:11:43.309] [bmv2] [D] [thread 7607] [30.0] [cxt 0] Deparser 'deparser': end
[17:11:43.309] [bmv2] [D] [thread 7609] [30.0] [cxt 0] Transmitting packet of size 58 out of port 2
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Processing packet received on port 2
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Parser 'parser': start
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Parser 'parser' entering state 'start'
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Extracting header 'ethernet'
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Parser state 'start': key is 0800
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] Bytes parsed: 14
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Parser 'parser' entering state 'parse_ipv4'
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Extracting header 'ipv4'
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Parser state 'parse_ipv4' has no switch, going to default next state
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] Bytes parsed: 34
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Parser 'parser': end
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Pipeline 'ingress': start
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] clone.p4(140) Condition "hdr.ipv4.isValid()" (node_2) is true
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] Applying table 'tbl_clone_packet'
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Looking up key:

[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Table 'tbl_clone_packet': miss
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Action entry is MyIngress.clone_packet - 
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] Action MyIngress.clone_packet
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] clone.p4(122) Primitive clone_preserving_field_list(CloneType.I2E, CLONE_ID, 0)
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] Applying table 'MyIngress.ipv4_lpm'
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Looking up key:
* hdr.ipv4.dstAddr    : 0a000202

[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Table 'MyIngress.ipv4_lpm': hit with handle 1
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Dumping entry 1
Match key:
* hdr.ipv4.dstAddr    : LPM       0a000202/32
Action entry: MyIngress.ipv4_forward - 80000000222,1,

[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Action entry is MyIngress.ipv4_forward - 80000000222,1,
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] Action MyIngress.ipv4_forward
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] clone.p4(114) Primitive standard_metadata.egress_spec = port
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] clone.p4(115) Primitive hdr.ethernet.srcAddr = hdr.ethernet.dstAddr
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] clone.p4(116) Primitive hdr.ethernet.dstAddr = dstAddr
[17:11:43.309] [bmv2] [T] [thread 7604] [31.0] [cxt 0] clone.p4(117) Primitive hdr.ipv4.ttl = hdr.ipv4.ttl - 1
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Pipeline 'ingress': end
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Cloning packet at ingress
[17:11:43.309] [bmv2] [D] [thread 7604] [31.0] [cxt 0] Egress port is 1
[17:11:43.309] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Pipeline 'egress': start
[17:11:43.309] [bmv2] [T] [thread 7606] [31.0] [cxt 0] Applying table 'MyEgress.dbg_table'
[17:11:43.310] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Looking up key:
* standard_metadata.ingress_port            : 0002
* standard_metadata.egress_spec             : 0000
* standard_metadata.egress_port             : 0001
* standard_metadata.instance_type           : 00000000
* standard_metadata.packet_length           : 00000036
* standard_metadata.enq_timestamp           : 0133766c
* standard_metadata.enq_qdepth              : 000000
* standard_metadata.deq_timedelta           : 00000037
* standard_metadata.deq_qdepth              : 000000
* standard_metadata.ingress_global_timestamp: 0000013375fd
* standard_metadata.egress_global_timestamp : 0000013376a3
* standard_metadata.mcast_grp               : 0000
* standard_metadata.egress_rid              : 0000
* standard_metadata.checksum_error          : 00

[17:11:43.310] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Table 'MyEgress.dbg_table': miss
[17:11:43.310] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Action entry is NoAction - 
[17:11:43.310] [bmv2] [T] [thread 7606] [31.0] [cxt 0] Action NoAction
[17:11:43.310] [bmv2] [T] [thread 7606] [31.0] [cxt 0] clone.p4(200) Condition "standard_metadata.instance_type == BMV2_V1MODEL_INSTANCE_TYPE_INGRESS_CLONE" (node_8) is false
[17:11:43.310] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Pipeline 'egress': end
[17:11:43.310] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Deparser 'deparser': start
[17:11:43.310] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Updating checksum 'cksum'
[17:11:43.310] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Deparsing header 'ethernet'
[17:11:43.310] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Deparsing header 'ipv4'
[17:11:43.310] [bmv2] [D] [thread 7606] [31.0] [cxt 0] Deparser 'deparser': end
[17:11:43.310] [bmv2] [D] [thread 7609] [31.0] [cxt 0] Transmitting packet of size 54 out of port 1
antoninbas commented 1 year ago

Did you configure the cloning session with runtime APIs? It doesn't look that way.

TLDart commented 1 year ago

Thank you for the hasty response, I indeed have not performed any configuration of that sort. Is there document or resource that shows how to do that? Best regards, Duarte

antoninbas commented 1 year ago

That depends on what API you are using. Since you seem to be using the p4lang tutorials as a starting point, try looking for clone_session_entries in the tutorials repo.

TLDart commented 1 year ago

Good afternoon, Indeed all I needed to do was to configure the mirror session. For this I used mirroring_add <clone_id> <egress_port> on the desired switch.

On a quick note before closing the issue, is there any document that lists all the _switchcli commands?

Best regards, Duarte.

jafingerhut commented 1 year ago

There is a document that lists them all, but it only documents some of them, mainly due to lack of time/interest/knowledge in people wanting to document the rest at a similar level of detail (if you want to add documentation to any of them in this file, go for it!): https://github.com/p4lang/behavioral-model/blob/main/docs/runtime_CLI.md

You can get a list of all commands and a brief description of its behavior and the parameters it takes by typing "help" or "help " at the prompt you get from running simple_switch_CLI.