Skip to content

Commit

Permalink
Introduce the SKB metadata extern (#4916)
Browse files Browse the repository at this point in the history
Signed-off-by: Mouse <mouse@mojatatu.com>
Co-authored-by: Mouse <mouse@mojatatu.com>
  • Loading branch information
vbnogueira and mouse-mt authored Dec 19, 2024
1 parent bed75a8 commit 3ec3732
Show file tree
Hide file tree
Showing 68 changed files with 2,982 additions and 370 deletions.
3 changes: 2 additions & 1 deletion backends/ebpf/codeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ bool CodeGenInspector::preorder(const IR::Declaration_Variable *decl) {
return false;
}

// We count on the optimizer to get rid of 64-bit arithmetic when it's unnecessary
static cstring getMask(P4::TypeMap *typeMap, const IR::Node *node) {
auto type = typeMap->getType(node, true);
cstring mask = cstring::empty;
if (auto tb = type->to<IR::Type_Bits>()) {
if (tb->size != 8 && tb->size != 16 && tb->size != 32 && tb->size != 64)
mask = " & ((1 << " + Util::toString(tb->size) + ") - 1)";
mask = " & ((1ULL << " + Util::toString(tb->size) + ") - 1)";
}
return mask;
}
Expand Down
255 changes: 225 additions & 30 deletions backends/tc/ebpfCodeGen.cpp

Large diffs are not rendered by default.

20 changes: 18 additions & 2 deletions backends/tc/ebpfCodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,25 @@ class EBPFTablePNA : public EBPF::EBPFTablePSA {
DECLARE_TYPEINFO(EBPFTablePNA, EBPF::EBPFTablePSA);
};

class IngressDeparserPNA;

class DeparserBodyTranslatorPNA : public EBPF::DeparserBodyTranslatorPSA {
public:
explicit DeparserBodyTranslatorPNA(const IngressDeparserPNA *deparser);

void processFunction(const P4::ExternFunction *function) override;
};

class IngressDeparserPNA : public EBPF::EBPFDeparserPSA {
public:
mutable bool touched_skb_metadata;

IngressDeparserPNA(const EBPF::EBPFProgram *program, const IR::ControlBlock *control,
const IR::Parameter *parserHeaders, const IR::Parameter *istd)
: EBPF::EBPFDeparserPSA(program, control, parserHeaders, istd) {}
: EBPF::EBPFDeparserPSA(program, control, parserHeaders, istd),
touched_skb_metadata(false) {
codeGen = new DeparserBodyTranslatorPNA(this);
}

bool addExternDeclaration = false;
bool build() override;
Expand Down Expand Up @@ -282,9 +296,11 @@ class EBPFControlPNA : public EBPF::EBPFControlPSA {
std::map<cstring, EBPFRegisterPNA *> pna_registers;
std::map<cstring, EBPFHashPNA *> pna_hashes;

mutable bool touched_skb_metadata;

EBPFControlPNA(const EBPF::EBPFProgram *program, const IR::ControlBlock *control,
const IR::Parameter *parserHeaders)
: EBPF::EBPFControlPSA(program, control, parserHeaders) {}
: EBPF::EBPFControlPSA(program, control, parserHeaders), touched_skb_metadata(false) {}

EBPFRegisterPNA *getRegister(cstring name) const {
auto result = ::P4::get(pna_registers, name);
Expand Down
149 changes: 149 additions & 0 deletions backends/tc/runtime/pna.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct pna_main_output_metadata_t {
*/
struct pna_global_metadata {
bool recirculated;
bool recirculate;
bool drop; // NOTE : no drop field in PNA metadata, so we keep drop state as internal metadata.
PortId_t egress_port;
enum MirrorType mirror_type;
Expand Down Expand Up @@ -460,4 +461,152 @@ static inline u32 bpf_p4tc_extern_random(u32 min, u32 max) {

return (min + bpf_get_prandom_u32()) % (max + 1);
}

#define BIT(x) (1 << x)

#define P4TC_SKB_META_SET_TSTAMP BIT(0)
#define P4TC_SKB_META_SET_MARK BIT(1)
#define P4TC_SKB_META_SET_CLASSID BIT(2)
#define P4TC_SKB_META_SET_TC_INDEX BIT(3)
#define P4TC_SKB_META_SET_QMAP BIT(4)
#define P4TC_SKB_META_SET_PROTO BIT(5)

struct p4tc_skb_meta_set {
__u64 tstamp;
__u32 mark;
__u16 tc_classid;
__u16 tc_index;
__u16 queue_mapping;
__be16 protocol;
__u32 bitmask;
};

static inline void
bpf_p4tc_skb_set_tstamp(struct __sk_buff *skb,
struct p4tc_skb_meta_set *meta_set, __u64 tstamp)
{
meta_set->tstamp = tstamp;
meta_set->bitmask |= P4TC_SKB_META_SET_TSTAMP;
}

static inline void
bpf_p4tc_skb_set_mark(struct __sk_buff *skb,
struct p4tc_skb_meta_set *meta_set, __u32 mark)
{
meta_set->mark = mark;
meta_set->bitmask |= P4TC_SKB_META_SET_MARK;
}

static inline void
bpf_p4tc_skb_set_tc_classid(struct __sk_buff *skb,
struct p4tc_skb_meta_set *meta_set, __u32 tc_classid)
{
meta_set->tc_classid = tc_classid;
meta_set->bitmask |= P4TC_SKB_META_SET_CLASSID;
}

static inline void
bpf_p4tc_skb_set_tc_index(struct __sk_buff *skb,
struct p4tc_skb_meta_set *meta_set, __u16 tc_index)
{
meta_set->tc_index = tc_index;
meta_set->bitmask |= P4TC_SKB_META_SET_TC_INDEX;
}

static inline void
bpf_p4tc_skb_set_queue_mapping(struct __sk_buff *skb,
struct p4tc_skb_meta_set *meta_set,
__u16 queue_mapping)
{
meta_set->queue_mapping = queue_mapping;
meta_set->bitmask |= P4TC_SKB_META_SET_QMAP;
}

static inline void
bpf_p4tc_skb_set_protocol(struct __sk_buff *skb,
struct p4tc_skb_meta_set *meta_set, __be16 protocol)
{
meta_set->protocol = protocol;
meta_set->bitmask |= P4TC_SKB_META_SET_PROTO;
}

int bpf_p4tc_skb_meta_set(struct __sk_buff *skb,
struct p4tc_skb_meta_set *skb_meta_set,
u32 skb_meta_set__sz) __ksym;

#define P4TC_SKB_META_GET_AT_INGRESS_BIT BIT(0)
#define P4TC_SKB_META_GET_FROM_INGRESS_BIT BIT(1)

struct p4tc_skb_meta_get {
u8 tc_at_ingress:1,
from_ingress:1;
u8 bitmask;
};

static inline __u64
bpf_p4tc_skb_get_tstamp(struct __sk_buff *skb,
struct p4tc_skb_meta_get *meta_get)
{
return skb->tstamp;
}

static inline __u16
bpf_p4tc_skb_get_tc_classid(struct __sk_buff *skb,
struct p4tc_skb_meta_get *meta_get)
{
return skb->tc_classid;
}

static inline __u16
bpf_p4tc_skb_get_tc_index(struct __sk_buff *skb,
struct p4tc_skb_meta_get *meta_get)
{
return skb->tc_index;
}

static inline __u16
bpf_p4tc_skb_get_queue_mapping(struct __sk_buff *skb,
struct p4tc_skb_meta_get *meta_get)
{
return skb->queue_mapping;
}

static inline __be16
bpf_p4tc_skb_get_protocol(struct __sk_buff *skb,
struct p4tc_skb_meta_get *meta_get)
{
return skb->protocol;
}

static inline int
bpf_p4tc_skb_get_tc_at_ingress(struct __sk_buff *skb,
struct p4tc_skb_meta_get *meta_get)
{
if (meta_get->bitmask & P4TC_SKB_META_GET_AT_INGRESS_BIT)
return meta_get->tc_at_ingress;

return -1;
}

static inline int
bpf_p4tc_skb_get_from_ingress(struct __sk_buff *skb,
struct p4tc_skb_meta_get *meta_get)
{
if (meta_get->bitmask & P4TC_SKB_META_GET_FROM_INGRESS_BIT)
return meta_get->from_ingress;

return -1;
}

static inline __u32
bpf_p4tc_skb_get_mark(struct __sk_buff *skb,
struct p4tc_skb_meta_get *meta_get)
{
return skb->mark;
}

int bpf_p4tc_skb_meta_get(struct __sk_buff *skb,
struct p4tc_skb_meta_get *skb_meta_get,
u32 skb_meta_get__sz) __ksym;

#endif /* P4C_PNA_H */
18 changes: 18 additions & 0 deletions p4include/tc/pna.p4
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,23 @@ extern Counter<W, S> {
}
// END:Counter_extern

extern void skb_get_meta();
extern bit<64> skb_get_tstamp();
extern bit<32> skb_get_mark();
extern bit<16> skb_get_tc_classid();
extern bit<16> skb_get_tc_index();
extern bit<16> skb_get_queue_mapping();
extern bit<16> skb_get_protocol();
extern bit<1> skb_get_tc_at_ingress();
extern bit<1> skb_get_from_ingress();
extern void skb_set_tstamp(in bit<64> dummy);
extern void skb_set_mark(in bit<32> dummy);
extern void skb_set_tc_classid(in bit<16> dummy);
extern void skb_set_tc_index(in bit<16> dummy);
extern void skb_set_queue_mapping(in bit<16> dummy);
extern void skb_set_protocol(in bit<16> dummy);
extern void skb_set_meta();

struct tc_ControlPath_Counter<W, S> {
@tc_key S index;
@tc_data W pkts;
Expand Down Expand Up @@ -610,6 +627,7 @@ struct pna_main_input_metadata_t {
// common fields initialized for all packets that are input to main
// parser, regardless of direction.
bool recirculated;
bool recirculate;
Timestamp_t timestamp;
ParserError_t parser_error;
ClassOfService_t class_of_service;
Expand Down
142 changes: 142 additions & 0 deletions testdata/p4tc_samples/skb_meta.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include <core.p4>
#include <tc/pna.p4>

/****** G L O B A L I N G R E S S M E T A D A T A *********/

struct my_ingress_metadata_t {
}

struct empty_metadata_t {
}

/* -*- P4_16 -*- */

/*
* CONST VALUES FOR TYPES
*/
const bit<8> IP_PROTO_TCP = 0x06;
const bit<16> ETHERTYPE_IPV4 = 0x0800;

/*
* Standard ethernet header
*/
header ethernet_t {
bit<48> dstAddr;
bit<48> 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 my_ingress_headers_t {
ethernet_t ethernet;
ipv4_t ipv4;
}

/*********************** P A R S E R **************************/
parser Ingress_Parser(
packet_in pkt,
out my_ingress_headers_t hdr,
inout my_ingress_metadata_t meta,
in pna_main_parser_input_metadata_t istd)
{

state start {
transition parse_ethernet;
}

state parse_ethernet {
pkt.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType) {
ETHERTYPE_IPV4: parse_ipv4;
default: reject;
}
}
state parse_ipv4 {
pkt.extract(hdr.ipv4);
transition select(hdr.ipv4.protocol) {
IP_PROTO_TCP : accept;
default: reject;
}
}
}

#define L3_TABLE_SIZE 2048

/***************** M A T C H - A C T I O N *********************/

control ingress(
inout my_ingress_headers_t hdr,
inout my_ingress_metadata_t meta,
in pna_main_input_metadata_t istd,
inout pna_main_output_metadata_t ostd
)
{
action send_nh(@tc_type("dev") PortId_t port, @tc_type("macaddr") bit<48> srcMac, @tc_type("macaddr") bit<48> dstMac) {

skb_get_meta();
skb_set_tc_classid(skb_get_tc_classid() + 1);
skb_set_tc_index(skb_get_tc_index() + 1);
skb_set_meta();
hdr.ethernet.srcAddr = (bit<48>)skb_get_tstamp() ^ srcMac;
hdr.ethernet.dstAddr = dstMac;
send_to_port(port);
}

action drop() {
drop_packet();
}

table nh_table {
key = {
hdr.ipv4.dstAddr : exact @tc_type("ipv4") @name("dstAddr");
}
actions = {
send_nh;
drop;
}
size = L3_TABLE_SIZE;
const default_action = drop;
}

apply {
if (hdr.ipv4.isValid() && hdr.ipv4.protocol == IP_PROTO_TCP) {
nh_table.apply();
}
}
}

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

control Ingress_Deparser(
packet_out pkt,
inout my_ingress_headers_t hdr,
in my_ingress_metadata_t meta,
in pna_main_output_metadata_t ostd)
{
apply {
pkt.emit(hdr.ethernet);
pkt.emit(hdr.ipv4);
}
}

/************ F I N A L P A C K A G E ******************************/

PNA_NIC(
Ingress_Parser(),
ingress(),
Ingress_Deparser()
) main;
Loading

0 comments on commit 3ec3732

Please sign in to comment.