NIKSS-vSwitch / nikss

Native In-Kernel P4-programmable Software Switch for Software-Defined Networking (previously PSA-eBPF)
Apache License 2.0
48 stars 4 forks source link

bridging user metadata from ingress to egress ? #99

Open zoxerus opened 1 year ago

zoxerus commented 1 year ago

trying to bridge the user metadata doesn't seem to work for the NIKSS switch, I get the following errors when trying to compile the generated C file:

simple_switch.c:531:1: error: expected expression
;
^
simple_switch.c:533:17: error: use of undeclared identifier 'normal_meta'
                normal_meta = meta;            }

I am modifying the basic forwarding example included in the NIKSS repository. my entire code is included below

#include <core.p4>
#include <psa.p4>

typedef bit<48>  EthernetAddress;
typedef bit<32>  IPv4Address;

struct empty_t {}

header ethernet_t {
    EthernetAddress dstAddr;
    EthernetAddress 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;
    bit<32> srcAddr;
    bit<32> dstAddr;
}

struct metadata {
    bit<32> ingress_port; 
}

struct headers {
    ethernet_t       ethernet;
    ipv4_t           ipv4;
}

parser IngressParserImpl(packet_in buffer,
                         out headers parsed_hdr,
                         inout metadata meta,
                         in psa_ingress_parser_input_metadata_t istd,
                         in empty_t resubmit_meta,
                         in empty_t recirculate_meta)
{
    state start {
        buffer.extract(parsed_hdr.ethernet);
        transition select(parsed_hdr.ethernet.etherType) {
            0x0800: parse_ipv4;
            default: accept;
        }
    }

    state parse_ipv4 {
        buffer.extract(parsed_hdr.ipv4);
        transition accept;
    }
}

parser EgressParserImpl(packet_in buffer,
                        out headers parsed_hdr,
                        inout metadata meta,
                        in psa_egress_parser_input_metadata_t istd,
                        in metadata normal_meta,
                        in empty_t clone_i2e_meta,
                        in empty_t clone_e2e_meta)
{
    state start {
        buffer.extract(parsed_hdr.ethernet);
        transition select(parsed_hdr.ethernet.etherType) {
            0x0800: parse_ipv4;
            default: accept;
        }
    }

    state parse_ipv4 {
        buffer.extract(parsed_hdr.ipv4);
        transition accept;
    }
}

control ingress(inout headers hdr,
                inout metadata meta,
                in    psa_ingress_input_metadata_t  istd,
                inout psa_ingress_output_metadata_t ostd)
{

    action do_forward(PortId_t egress_port) {
        meta.ingress_port = (bit<32>) istd.ingress_port;
        send_to_port(ostd, egress_port);
    }

    table tbl_fwd {
        key = {
            hdr.ethernet.dstAddr : exact;
        }
        actions = { do_forward; NoAction; }
        default_action = NoAction;
        size = 100;
    }

    apply {
        tbl_fwd.apply();
    }
}

control egress(inout headers hdr,
               inout metadata meta,
               in    psa_egress_input_metadata_t  istd,
               inout psa_egress_output_metadata_t ostd)
{
    apply { }
}

control CommonDeparserImpl(packet_out packet,
                           inout headers hdr)
{
    apply {
        packet.emit(hdr.ethernet);
        packet.emit(hdr.ipv4);
    }
}

control IngressDeparserImpl(packet_out buffer,
                            out empty_t clone_i2e_meta,
                            out empty_t resubmit_meta,
                            out metadata normal_meta,
                            inout headers hdr,
                            in metadata meta,
                            in psa_ingress_output_metadata_t istd)
{
    CommonDeparserImpl() cp;
    apply {
        cp.apply(buffer, hdr);
        if (psa_normal(istd)) {
            normal_meta = meta;
        }
    }
}

control EgressDeparserImpl(packet_out buffer,
                           out empty_t clone_e2e_meta,
                           out empty_t recirculate_meta,
                           inout headers hdr,
                           in metadata meta,
                           in psa_egress_output_metadata_t istd,
                           in psa_egress_deparser_input_metadata_t edstd)
{
    CommonDeparserImpl() cp;
    apply {
        cp.apply(buffer, hdr);
    }
}

IngressPipeline(IngressParserImpl(),
                ingress(),
                IngressDeparserImpl()) ip;

EgressPipeline(EgressParserImpl(),
               egress(),
               EgressDeparserImpl()) ep;

PSA_Switch(ip, PacketReplicationEngine(), ep, BufferingQueueingEngine()) main;
osinstom commented 1 year ago

This way (using "normal_meta" to bridge metadata from ingress deparser to egress parser) is not yet supported by the PSA-eBPF compiler.

As a workaround, I'd suggest using an additional packet header carrying metadata in front of a packet, as shown in https://github.com/p4lang/p4c/blob/main/backends/ebpf/tests/p4testdata/bridged-metadata.p4.