Code Monkey home page Code Monkey logo

p4c-xdp's Introduction

p4c-xdp

This project has been archived. For a more complete ebpf XDP compiler please see the open-source p4c repository, in particular the p4c-ebpf compiler.

Main Build Apache licensed GPL licensed

This work presents a P4 compiler backend targeting XDP, the eXpress Data Path. P4 is a domain-specific language describing how packets are processed by the data plane of a programmable network elements, including network interface cards, appliances, and virtual switches. With P4, programmers focus on defining the protocol parsing, matching, and action executions, instead of the platform-specific language or implementation details.

XDP is designed for users who want programmability as well as performance. XDP allows users to write a C-like packet processing program and loads into the device driver's receiving queue. When the device observes an incoming packet, before hanging the packet to the Linux stack, the user-defined XDP program is triggered to execute against the packet payload, making the decision as early as possible.

We bring together the benefits of the two: P4 and XDP. To get started, first you need to setup the P4-16 compiler, then this project is an extension to the P4-16. To execute the XDP, you need Linux kernel version >= 4.10.0-rc7+ due to some BPF verifier limitations

Presentations

Installation

Docker/Vagrant

Please see Dockerfile. There is also a public docker image available as u9012063/p4xdp

$ docker pull u9012063/p4xdp

will pull the latest image. However, the XDP BPF code has dependency on your kernel version. Currently for some complicated cases we require kernel >= 4.10.0-rc7. So a vagrant box is also provided with kernel 4.10.0-rc8.

$ vagrant init u9012063/p4xdp
$ vagrant up
$ vagrant ssh
ubuntu@ubuntu-xenial:~$ sudo su
root@ubuntu-xenial:/home/ubuntu# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
u9012063/p4xdp      latest              3c77fbbd84e5        41 hours ago        2.469 GB
root@ubuntu-xenial:/home/ubuntu# docker run -it -u root --privileged <IMAGE ID>

Will boot this VM, pull the docker image, and you can try p4c-xdp.

P4-16 Compiler

First you need to follow the installation guide of P4-16 When you have P4-16 compiler, then add this project as an extension. Assuming you have P4-16 at your dir ~/p4c/, to setup P4C-XDP:

cd ~/p4c/
mkdir extensions
cd extensions
git clone https://github.com/vmware/p4c-xdp.git
ln -s ~/p4c p4c-xdp/p4c

Now that you have cloned p4c-xdp at ~/p4c/extensions/p4c-xdp, the next step is to recompile p4c:

cd ~/p4c/
mkdir -p build
cd build/
cmake ..
make

This generates a p4c-xdp binary in ~/p4c/build. And install the xdp test target in backends/ebpf/targets. Next create a soft link to the binary:

cd ~/p4c/extensions/p4c-xdp
ln -s ~/p4c/build/p4c-xdp p4c-xdp

And a soft link to the test runtime:

cd ~/p4c/extensions/p4c-xdp
ln -s ~/p4c/backends/ebpf/run-ebpf-test.py run-ebpf-test.py

Now you can run the p4c-xdp tests:

cd ~/p4c/build/
make check-xdp

This will check your llvm and clang version, compile all .p4 files, generate .c files, and load them into the kernel to be checked by the BPF verifier.

XDP: eXpress Data Path

XDP is a packet processing mechanism implemented within the device driver with eBPF. Currently to compile a P4 to C program, use

	# ./p4c-xdp --target xdp -o <output_c_file> <input_p4>
	./p4c-xdp --target xdp -o /tmp/xdp1.c xdp1.p4

then you need to compile the xdp1.c to eBPF bytecode, xdp1.o, then load it into your driver. To compile a single .c file

clang -Wno-unused-value -Wno-pointer-sign \
		-Wno-compare-distinct-pointer-types \
		-Wno-gnu-variable-sized-type-not-at-end \
		-Wno-tautological-compare \
		-O2 -emit-llvm -g -c /tmp/xdp1.c -o -| llc -march=bpf -filetype=obj -o /tmp/xdp1.o

Then load it into the driver with XDP support

    ip link set dev $DEV xdp obj xdp1.o verb

to unload the XDP object

    ip link set dev $DEV xdp off

Sample Code

Please see the tests folder Simply run 'make' will start the build

Related BPF/XDP work

  • Dive into BPF: a list of reading material, Quentin Monnet link
  • BPF: Next Generation of Programmable Datapath by Thomas Graf, OVS Conf 2016 video
  • Fast Programmable Networks & Encapsulated Protocols, David S. Miller, netdev 1.2 video

License

The p4c-xdp/lib/* contains BPF loader licensed under the General Public License, Version 2.0. The rest of p4c-xdp components are licensed under the Apache License, Version 2.0.

TODO

  • Remove the private kernel patch requirement when latest kernel with BPF fixed is ready
  • Apply the workaround of BPF_MAX_STACK
  • Control plane example using perf_event_output

p4c-xdp's People

Contributors

chengchuntu avatar fruffy avatar hiroyuki-sato avatar williamtu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

p4c-xdp's Issues

xdp10.p4: counter support

add xdp10.p4, compile and there are missing definitions for

clang \
	-D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
	-Wno-compare-distinct-pointer-types \
	-Wno-gnu-variable-sized-type-not-at-end \
	-Wno-tautological-compare \
	-O2 -emit-llvm -g -c xdp10.c -o -| llc -march=bpf -filetype=obj -o xdp10.o
xdp10.c:173:21: error: use of undeclared identifier 'counters_value'
                    counters_value *value;
                    ^
xdp10.c:173:37: error: use of undeclared identifier 'value'
                    counters_value *value;

adding the following in xdp10.h solves the problem

typedef u32 counters_value;
typedef u32 counters_key;

Reimplement linux/samples xdp programs in P4

A nice way to show the usefulness of the compiler is to reimplement most of the xdp examples in the /linux/samples folder in pure P4 code.
This is also a good way to determine discrepancies or detect missing features.

bpf verifier: register becomes inv when LSH then RSH

R9 is a pkt ptr, after <<32 and >>32, it becomes invalid ?

 R0=pkt(id=0,off=25,r=58) R1=imm2,min_value=2,max_value=2 R2=inv56 R3=inv60,min_value=0,max_value=15 R4=imm6,min_value=6,max_value=6 R5=pkt_end R6=inv R7=inv60,min_value=0,max_value=15 R8=inv 
R9=pkt(id=0,off=0,r=0) R10=fp fp-184=imm fp-176=imm
407: (b7) r1 = 1
408: (b7) r0 = 0
409: (63) *(u32 *)(r10 -12) = r0
410: (63) *(u32 *)(r10 -16) = r1
411: (67) r5 <<= 32
412: (77) r5 >>= 32
413: (67) r9 <<= 32
414: (77) r9 >>= 32
415: (bf) r1 = r9
416: (07) r1 += 14
417: (2d) if r1 > r5 goto pc+188
 R0=imm0,min_value=0,max_value=0 R1=inv31 R2=inv56 R3=inv60,min_value=0,max_value=15 R4=imm6,min_value=6,max_value=6 R5=inv32 R6=inv R7=inv60,min_value=0,max_value=15 R8=inv 
R9=inv32 R10=fp fp-184=imm fp-176=imm fp-16=imm fp-8=imm
418: (79) r1 = *(u64 *)(r10 -168)
419: (73) *(u8 *)(r9 +0) = r1
R9 invalid mem access 'inv'

default_action map does not get populated

When setting default_action in p4, we create a map and look it up the index 0 entry "bpf_map_lookup_elem(&dstmactable_defaultAction, &ebpf_zero);"
but we don't actually populate this map entry with the default action.
Now it always assumes the first entry in actions as default.

Not critical issue. I could work around it by putting the default at index 0

control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
    action SetTTL_action(action_md_t md) 
    {   
        hd.ipv4.ttl = md.ttl;
    }   
    action Fallback_action()
    {   
        xout.drop = false;
    }   
    action Drop_action()
    {   
        xout.drop = true;
    }   
    table dstmactable() {
        key = { hd.ethernet.protocol : exact; }
        actions = { 
            SetTTL_action;      // miss will trigger this one index 0
            Fallback_action;
            Drop_action;
        }
        default_action = Drop_action;  // default entry at index 2 
        implementation = hash_table(64);
    }   
    apply {
        dstmactable.apply();
        xout.output_port = 0;
    }   
}

Add userspace runtime to the xdp backend

The xdp compiler currently only features a kernel runtime. It would be nice to add a userspace emulation to verify forwarding behaviour and packet modification in userspace.

duplicate SEC in ebpf C file when using p4c-xdp

when testing the latest with p4c-xdp, the generated C code has:

SEC("ebpf_filter")
SEC("prog")
int ebpf_filter(struct xdp_md* skb){
    struct Headers_t headers = { 
        .ethernet = { 

maybe we should allow users to specify the SEC name, for example

./p4c-xdp --target xdp --sec <mysection name> -o <in> src.p4

if not, I'd prefer using "prog" since it is default in ip tool.

Compiler error with unisgned integers

Hello,
As we know, the compilation process involves two parts P4 -> P4c -> .c and .h and .c -> .o. In the /p4c-xdp/tests/ folder, we ran the make command which completes both the phases of compilation.

When compiling with clang from the .c file to .o, the following error is encountered:

In file included from xdp2.c:3:
./xdp2.h:16:5: error: unknown type name 'u32'
u32 input_port; /* bit<32> /
^
./xdp2.h:21:5: error: unknown type name 'u32'
u32 output_port; /
bit<32> */
^
.
.
.
./xdp2.h:44:5: error: unknown type name 'u8'
u8 ebpf_valid;
^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
Makefile:55: recipe for target 'xdp2.o' failed
make: *** [xdp2.o] Error 1

The program terminates with these errors. Can someone please guide us regarding this issue?
Thank you for your time and help.
Sincerely,

Unexpected behavior when running xdp3.o

Hi, I'm testing the xdp3.p4 which parse L2, L3 and action could be drop or pass.
The table is described like this:

table dstmactable {
        key = { hdr.ethernet.destination : exact; }
        actions = {
            Fallback_action;
            Drop_action;
        }
        default_action = Drop_action;
        implementation = hash_table(64);
    }

After loading xdp3, I found that all the packets were passed to the kernel.
My understanding is that if the default action of a table is Drop_action, Then if a table has no entries or the packet does not match the table entries, The default action will be executed on the packet. I didn't add any entries to the dstmactable table through a control plane program. So the packet should be the default action: they should be dropped . Is my understanding right?
But the fact seems not like what I thought.

kernel 4.10.1 bpf verifier

kernel image 4.10.1 should have our BPF patches, however installing it in my vagrant box
http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.10.1/
still fails as below:

 R0=inv56 R1=pkt(id=0,off=0,r=34) R2=pkt_end R3=imm272,min_value=272,max_value=272 R4=inv R5=inv56 R6=ctx R7=inv56,min_value=0,max_value=255 R8=imm0,min_value=0,max_value=0 R9=inv R10=fp
441: (bf) r5 = r3
442: (07) r5 += 32
443: (18) r4 = 0xfffffff8
445: (5f) r5 &= r4
446: (77) r5 >>= 3
447: (bf) r0 = r1
448: (0f) r0 += r5
cannot add integer value with 3 upper zero bits to ptr_to_packet

xdp8.p4: ip csum update

I forgot whether we want to do csum update at this moment or later. But let me keep track of it.
xdp8.p4 will by default write ttl=4, and my working implementation of csum update is below

--- a/tmp/xdp8.c
+++ b/tmp/xdp8.c.0
@@ -309,10 +309,16 @@ int ebpf_filter(struct xdp_md* skb){
 ;
             /* packet.emit(hd.ipv4)*/
             if (hd.ipv4.ebpf_valid) {
+                u32 csum = 0, i = 0;
+                u16 *iph;
+
                 if (ebpf_packetEnd < ebpf_packetStart + BYTES(ebpf_packetOffsetInBits + 160)) {
                     ebpf_errorCode = PacketTooShort;
                     goto ebpf_end;
                 }
+
+                iph = (u16 *)(ebpf_packetStart + BYTES(ebpf_packetOffsetInBits));
+
                 ebpf_byte = ((char*)(&hd.ipv4.version))[0];
                 write_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte) << 4);
                 ebpf_packetOffsetInBits += 4;
@@ -374,6 +380,13 @@ int ebpf_filter(struct xdp_md* skb){
                 ebpf_byte = ((char*)(&hd.ipv4.dstAddr))[3];
                 write_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte) << 0);
                 ebpf_packetOffsetInBits += 32;
+
+                /* update csum, the ip csum is at 10 byte offset */
+                *(iph + 5) = 0;
+                for (i = 0; i < (20>>1); i++)
+                    csum += iph[i];
+
+                *(iph + 5) = ~((csum & 0xffff) + (csum >> 16));
             }
 ;
         }

eBPF table not created

in xdp4.p4, I expect a ebpf table should be created, but got this error

root@osboxes:~/p4c/extensions/p4c-xdp/tests# make
p4c-xdp -I ../  --target xdp -o xdp4.c xdp4.p4;
xdp4.p4(58): warning: Table dstmactable is not used; removing
    table dstmactable() {
          ^^^^^^^^^^^

the xdp4.p4, I also pushed the xdp4.p4

control Ingress(inout Headers hdr, in xdp_input xin, out xdp_output xout) {
    bool xoutdrop = false;
    action Fallback_action()
    {
        xoutdrop = false;
    }   
    action Drop_action()
    {
        xoutdrop = true;
    }   
    table dstmactable() {
        key = { hdr.ethernet.destination : exact; }
        actions = { 
            Fallback_action;
            Drop_action;
        }
        default_action = Drop_action; 
        implementation = hash_table(64);
    }   
    apply {
        xout.output_port = 0;
        xout.drop = xoutdrop;
    }   
}

Generated struct identifier has a dot

#On xdp3.h

In file included from xdp3.c:3:
./xdp3.h:53:15: error: expected identifier or '('
struct Ingress.dstmactable_key {
              ^
./xdp3.h:57:12: error: expected '= constant-expression' or end of enumerator definition
    Ingress.Fallback_action,
           ^
./xdp3.h:58:5: error: redefinition of enumerator 'Ingress'
    Ingress.Drop_action,
    ^
./xdp3.h:57:5: note: previous definition is here
    Ingress.Fallback_action,
    ^
./xdp3.h:58:12: error: expected '= constant-expression' or end of enumerator definition
    Ingress.Drop_action,

in the source code

struct Headers {
    struct Ethernet ethernet; /* Ethernet */
    struct IPv4 ipv4; /* IPv4 */
};

struct Ingress.dstmactable_key {
    u64 field0; /* hdr.ethernet.destination */
};
enum dstmactable_actions {
    Ingress.Fallback_action,
    Ingress.Drop_action,
};

currently travis failed due to this issue:
https://api.travis-ci.org/v3/job/336961449/log.txt

how to implement a forwoading function using XDP_TX based on xdp7.p4

Hi,
I want to implement a simple forwarding function based on xdp7.p4 by using XDP_TX.
What I thought is B send packets to A , then I load xdp program on A's driver, and then A modify the packet's mac address, ip address , tcp port .After all these , the modified packet is sent to C by using XDP_TX.
What the program does is set the packets' four tuple and mac address from B. And I write like this:

/*
    This program is based on xdp7.p4. The goal is to implement a simple forward behavior 
    by set the static ip dstAddr, tcp srcPort and dstPort.
*/

#include "xdp_model.p4"

header Ethernet {
    bit<48> destination;
    bit<48> source;
    bit<16> protocol;
}

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

header icmp_t {
    bit<16> typeCode;
    bit<16> checksum;
}

header tcp_t {
    bit<16> srcPort;
    bit<16> dstPort;
    bit<32> seqNo;
    bit<32> ackNo;
    bit<4>  dataOffset;
    bit<4>  res;
    bit<8>  flags;
    bit<16> window;
    bit<16> checksum;
    bit<16> urgentPtr;
}

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


struct Headers {
    Ethernet ethernet;
    IPv4     ipv4;
    tcp_t   tcp;
    udp_t   udp;
    icmp_t icmp;
}

parser Parser(packet_in packet, out Headers hd) {
    state start {
        packet.extract(hd.ethernet);
        transition select(hd.ethernet.protocol) {
            16w0x800: parse_ipv4;
            default: accept;
        }
    }
    state parse_ipv4 {
        packet.extract(hd.ipv4);
        transition select(hd.ipv4.protocol) {
            8w6: parse_tcp;
            8w17: parse_udp;
            8w1: parse_icmp;
            default: accept;
        }
    }
    state parse_icmp {
        packet.extract(hd.icmp);
        transition accept;
    }
    state parse_tcp {
        packet.extract(hd.tcp);
        transition accept;
    }
    state parse_udp {
        packet.extract(hd.udp);
        transition accept;
    }
}

control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {

    bool xoutdrop = false;
    // from, to are host byte order
    bit<16> from;
    bit<16> to;
    bit<32> from_addr;
    bit<32> to_addr;
    bit<48> tmp;

    action Fallback_action()
    {

	// exchange ethernet's destination and source 
        tmp = hd.ethernet.source;
	hd.ethernet.source = hd.ethernet.destination;
        hd.ethernet.destination = tmp; 

        // TCP: set the packet's srcPort = 6666 , dstPort = 8888

        from = hd.tcp.srcPort;
        // srcPort: 6666
        to = 16w0x1a0a;    
        hd.tcp.srcPort = to;
        hd.tcp.checksum = csum_replace2(hd.tcp.checksum, from, to);
	    
        from = hd.tcp.dstPort;
        // dstPort: 8888
	to = 16w0x22b8;    
	hd.tcp.dstPort = to;
	hd.tcp.checksum = csum_replace2(hd.tcp.checksum, from, to);

        // IP: set the packet's srcAddr = dstAddr ,dstAddr = 172.16.100.1

        from_addr = hd.ipv4.srcAddr;
        // srcAddr = dstAddr
        to_addr = hd.ipv4.dstAddr;
        hd.ipv4.srcAddr = to_addr;
        hd.ipv4.checksum = csum_replace4(hd.ipv4.checksum, from_addr, to_addr);
        hd.tcp.checksum = csum_replace4(hd.tcp.checksum, from_addr, to_addr);
	    
        from_addr = hd.ipv4.dstAddr;
	// dstAddr = 172.16.100.1
        to_addr = 32w0xac106401;
	hd.ipv4.checksum = csum_replace4(hd.ipv4.checksum, from_addr, to_addr);
	hd.tcp.checksum = csum_replace4(hd.tcp.checksum, from_addr, to_addr);


        xoutdrop = false;
    }

    action Drop_action()
    {
        xoutdrop = true;
    }

    table dstmactable {
        key = { hd.ethernet.protocol : exact; }
        actions = {
            Fallback_action;
            Drop_action;
        }
        default_action = Fallback_action;
        implementation = hash_table(64);
    }

    apply {
        dstmactable.apply();
        xout.output_port = 0;
        // action set to XDP_TX
        xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_TX;
    }
}

control Deparser(in Headers hdrs, packet_out packet) {
    apply {
        packet.emit(hdrs.ethernet);
        packet.emit(hdrs.ipv4);

    // hit Verifier MAX_BPF_STACK issue
    //    packet.emit(hdrs.tcp);
    //    packet.emit(hdrs.udp);

        packet.emit(hdrs.icmp);
        packet.emit(hdrs.udp);
        packet.emit(hdrs.tcp);
    }
}

xdp(Parser(), Ingress(), Deparser()) main;

And I update the checksum . However this program could be compiled and loaded but seems not work as what I want.
Do I need to add ebpf_ipv4_checksum() to recalc the ipv4 checksum or anything else I forget to update ?
Could you give me some advices?
Thanks a lot!

What is the difference between bpf_obj_get() in libbpf.h and BPF_OBJ_GET() in init_tables()

I notice that there are both functions to get map descriptor and update in the control plane of user_xdp5.c and the header of xdp5.h .
In user_xdp5.c , it's

fd = bpf_obj_get(MAP_PATH TABLE);
[...]
ret = bpf_update_elem(fd, &key, &value, BPF_ANY);

In xdp5.h, it's

int tableFileDescriptor = BPF_OBJ_GET(MAP_PATH "/Ingress_dstmactable_defaultAction");
[...]
int ok = BPF_USER_MAP_UPDATE_ELEM(tableFileDescriptor, &ebpf_zero, &value, BPF_ANY);

I know the lowercase function in user_xdp5.c actually is from libbpf.h which finally calls the syscall:

return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
# or
return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));

But where is the captital function BPF_OBJ_GET() definition ? Why use this function in xdp.h ?
And I did some test that I use lowercase function bpf_obj_get() in xdp5.h to replace BPF_OBG_GET(). It seems work

After google it , I didn't find any source code in linux kernel matches this . And just know that BPF_OBJ_GET is a type of bpf_cmd in /linux/bpf.h

xdp4.p4 compile error

clang \
	-D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
	-Wno-compare-distinct-pointer-types \
	-Wno-gnu-variable-sized-type-not-at-end \
	-Wno-tautological-compare \
	-O2 -emit-llvm -g -c xdp4.c -o -| llc -march=bpf -filetype=obj -o xdp4.o
xdp4.c:212:30: error: use of undeclared identifier 'hdr'; did you mean 'hd'?
                key.field0 = hdr.ethernet.destination;
                             ^~~
                             hd
xdp4.c:102:20: note: 'hd' declared here
    struct Headers hd = {
                   ^
xdp4.c:212:28: error: array type 'char [6]' is not assignable
                key.field0 = hdr.ethernet.destination;
                ~~~~~~~~~~ ^
2 errors generated.

Unhandled packet method packet.lookahead

I tried to port P4C tutorial program - "calc" to XDP. The compiling failed with following error:
p4c-xdp --Werror --target xdp -o calc.c calc.p4;
terminate called after throwing an instance of 'Util::CompilerBug'
what(): In file: /home/wyklq/p4c/extensions/p4c-xdp/p4c/backends/ebpf/ebpfParser.cpp:294
Compiler Bug: calc.p4(114): Unhandled packet method packet.lookahead;
transition select(packet.lookahead<p4calc_t>().p,

The P4 source code is (".txt" is added to support github upload):
calc.p4.txt

decap, writing less data to xdp

This error happens when not emitting ethernet header
when testing the same case without icmp hader, it works OK.

control Deparser(in Headers hdrs, packet_out packet) {
    apply {
        //packet.emit(hdrs.ethernet);
        packet.emit(hdrs.ipv4);
        packet.emit(hdrs.icmp);
    }   
}

BPF verifier

R0=imm0,min_value=0,max_value=0 R1=pkt(id=0,off=0,r=4) R2=pkt_end R3=fp-12 R4=imm4,min_value=4,max_value=4 R5=pkt(id=0,off=4,r=4) R6=ctx R7=imm0,min_value=0,max_value=0 R8=inv,min_value=0,max_value=0 R9=inv R10=fp
269: (bf) r2 = r0
270: (77) r2 >>= 3
271: (bf) r4 = r1
272: (0f) r4 += r2
addition of negative constant to packet pointer is not allowed

LLVM objdump

; if (hd.icmp.ebpf_valid) {
     261:	r4 = *(u64 *)(r10 - 40)
     262:	if r4 == 0 goto 29
; if (ebpf_packetEnd < ebpf_packetStart + BYTES(ebpf_packetOffsetInBits + 32)) {
     263:	r4 = r0
     264:	r4 += 32
     265:	r4 >>= 3
     266:	r5 = r1
     267:	r5 += r4
     268:	if r5 > r2 goto 23
; write_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte) << 0);
     269:	r2 = r0
     270:	r2 >>= 3
     271:	r4 = r1
     272:	r4 += r2
     273:	r2 = *(u64 *)(r10 - 80)
     274:	*(u8 *)(r4 + 0) = r2
; ebpf_packetOffsetInBits += 8;
     275:	r0 |= 8
; write_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte) << 0);
     276:	r2 = r0

patch llvm and kernel net-next

the latest LLVM will also check the 512 byte BPF stack size. So we fails earlier at compiling the object instead of loading to verifier. Patch llvm and kernel net-next to 4096.

diff --git a/lib/Target/BPF/BPFRegisterInfo.cpp b/lib/Target/BPF/BPFRegisterInfo.cpp
index 7925bee..2636acb 100644
--- a/lib/Target/BPF/BPFRegisterInfo.cpp
+++ b/lib/Target/BPF/BPFRegisterInfo.cpp
@@ -44,7 +44,7 @@ BitVector BPFRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
 
 static void WarnSize(int Offset, MachineFunction &MF, DebugLoc& DL)
 {
-  if (Offset <= -512) {
+  if (Offset <= -4096) {
       auto F = MF.getFunction();
       DiagnosticInfoUnsupported DiagStackSize(*F,
           "Looks like the BPF stack limit of 512 bytes is exceeded. "

patch kernel net-next

--- a/arch/x86/net/bpf_jit.S
+++ b/arch/x86/net/bpf_jit.S
@@ -19,7 +19,7 @@
  */
 #define SKBDATA        %r10
 #define SKF_MAX_NEG_OFF    $(-0x200000) /* SKF_LL_OFF from filter.h */
-#define MAX_BPF_STACK (512 /* from filter.h */ + \
+#define MAX_BPF_STACK (4096 /* from filter.h */ + \
        32 /* space for rbx,r13,r14,r15 */ + \
        8 /* space for skb_copy_bits */)
 
diff --git a/include/linux/filter.h b/include/linux/filter.h
index e4eb254..fb532fc 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -55,7 +55,8 @@ struct bpf_prog_aux;
 #define MAX_BPF_JIT_REG                (MAX_BPF_REG + 1)
 
 /* BPF program can access up to 512 bytes of stack space. */
-#define MAX_BPF_STACK  512
+//#define MAX_BPF_STACK        512
+#define MAX_BPF_STACK  4096
 
 #define BPF_TAG_SIZE   8

xdp4.c fails compilation

error message

../p4c-xdp -I ../p4include --target xdp -o xdp4.c xdp4.p4;
clang \
	-D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
	-Wno-compare-distinct-pointer-types \
	-Wno-gnu-variable-sized-type-not-at-end \
	-Wno-tautological-compare \
	-O2 -emit-llvm -g -c xdp4.c -o -| llc -march=bpf -filetype=obj -o xdp4.o
xdp4.c:179:57: error: extraneous ')' before ';'
                &key.field0, &hd.ethernet.destination, 6);
                                                        ^

due to

                /* construct key */
                struct dstmactable_key key = {}; 
                &key.field0, &hd.ethernet.destination, 6); 

not sure if it is correct, but it works with the following patch

--- a/backends/ebpf/ebpfTable.cpp
+++ b/backends/ebpf/ebpfTable.cpp
@@ -275,7 +275,7 @@ void EBPFTable::emitKey(CodeBuilder* builder, cstring keyName) {
 
         builder->emitIndent();
         if (memcpy) {
-            builder->appendFormat("&%s.%s, &", keyName.c_str(), fieldName.c_str());
+            builder->appendFormat("memcpy(&%s.%s, &", keyName.c_str(), fieldName.c_str());
             codeGen->visit(c->expression);
             builder->appendFormat(", %d)", scalar->bytesRequired());
         } else {

bpf verifier error

The patch fixes the verifier error due to skb->data and data_end checking.
We have to follow the way verifier checking the packet boundary
if (data + offset > data_end) ...
With this patch, I test TCP parsing and works OK. However, I also mark out the parse_vlan and parse_ipv6. I still don't know why they cause verifier failed.
p4-xdp1.diff.txt

xdp15.p4: encap an additional header

At Deparser stage, can I unconditionally emit a new header?
so at xdp15.p4, I add a new header

/* encap my own header */
header myhdr_t {
    bit<32> timestamp;
    bit<32> id; 
}
control Ingress(inout Headers hdr, in xdp_input xin, out xdp_output xout) {
... <skip> ...
    apply {
        hdr.myhdr.id = 0xfefefefe; // get ID from map or else
        hdr.myhdr.timestamp = 0xabababab; // get TS from system
        dstmactable.apply();
        xout.output_port = 0;
        xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
    }
}
control Deparser(in Headers hdrs, packet_out packet) {
    apply {
        packet.emit(hdrs.myhdr);    // I want to insert in front of ethernet
        packet.emit(hdrs.ethernet);
        packet.emit(hdrs.ipv4);
    }
}

However, the generated C code will always check the valid bit (hd.myhdr.ebpf_valid) and since it's not part of the packet, it is always false and emit doesn't happen.

XDP12 Verifier: cannot add integer value with 0 upper zero bits to ptr_to_packet

This is related to #4
encounter the following verifier error. I guess this is similar to the previous one, but when spill the register to stack and restore, the imm upper zero bits state is missing?

 R0=imm0,min_value=0,max_value=0 R1=imm58,min_value=58,max_value=58 R3=pkt(id=0,off=58,r=58) R4=inv61 R5=pkt_end R6=imm144,min_value=144,max_value=144 R7=imm0,min_value=0,max_value=0 R8=ctx R9=pkt(id=0,off=0,r=58) R10=fp
260: (bf) r5 = r6
261: (47) r5 |= 12
262: (bf) r1 = r5
263: (07) r1 += 44
264: (77) r1 >>= 3
265: (7b) *(u64 *)(r10 -64) = r1
266: (bf) r7 = r5
267: (07) r7 += 36
268: (77) r7 >>= 3
269: (bf) r0 = r5
270: (07) r0 += 20
271: (77) r0 >>= 3
272: (bf) r1 = r5
273: (07) r1 += 52
274: (77) r1 >>= 3
275: (77) r6 >>= 3
276: (79) r2 = *(u64 *)(r10 -24)
277: (bf) r2 = r5
278: (77) r2 >>= 3
279: (7b) *(u64 *)(r10 -184) = r2
280: (07) r5 += 180
281: (77) r5 >>= 3
282: (bf) r4 = r9
283: (0f) r4 += r5
284: (47) r5 |= 1
285: (bf) r3 = r9
286: (0f) r3 += r6
287: (bf) r6 = r9
288: (0f) r6 += r1
289: (47) r1 |= 1
290: (bf) r2 = r9
291: (0f) r2 += r0
292: (7b) *(u64 *)(r10 -312) = r2
293: (bf) r2 = r9
294: (79) r0 = *(u64 *)(r10 -184)
295: (0f) r2 += r0
cannot add integer value with 0 upper zero bits to ptr_to_packet

The objdump

; hd.ipv6.version = (u8)((load_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits)) >> 4) & EBPF_MASK(u8, 4));
     285:	r3 = r9
     286:	r3 += r6
     287:	r6 = r9
     288:	r6 += r1
; hd.ipv6.srcAddr[1] = (u8)((load_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 1) >> 0));
     289:	r1 |= 1
; hd.ipv6.payloadLen = (u16)((load_half(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits))));
     290:	r2 = r9
     291:	r2 += r0
     292:	*(u64 *)(r10 - 312) = r2
; hd.ipv6.flowLabel = (u32)((load_word(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits)) >> 8) & EBPF_MASK(u32, 20));
     293:	r2 = r9
     294:	r0 = *(u64 *)(r10 - 184)
     295:	r2 += r0
     296:	*(u64 *)(r10 - 336) = r2
; hd.ipv6.nextHdr = (u8)((load_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits))));

Failed to run the test cases due to bpf header missing on fresh Ubuntu16.04

Hi,

After building p4-xdp on Ubuntu16.04, I'd like to run all test cases to valid p4-xdp correctly working! However, do make under the tests directory, some error messages come out! plz see below~

In my guess, it seems can't find the proper bpf header, not in "/usr/include/linux/bpf.h". In the file, for example, there is no type BPF_PROG_TYPE_XDP in enum bpf_prog_type!

I installed linux-headers-4.10.0-28-generic and included it in Makefile under lib directory, but it conflicts with the existing headers!

========================
p4@p4-VirtualBox:/workspace/p4c/extensions/p4c-xdp/tests$ uname -a
Linux p4-VirtualBox 4.10.0-28-generic #32
16.04.2-Ubuntu SMP Thu Jul 20 10:19:48 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

p4@p4-VirtualBox:~/workspace/p4c/extensions/p4c-xdp/tests$ make
make -C ../lib/
make[1]: Entering directory '/home/p4/workspace/p4c/extensions/p4c-xdp/lib'
gcc -I -g -c bpf_load.c
In file included from bpf_load.c:25:0:
bpf_helpers.h:45:11: error: ‘BPF_FUNC_get_stackid’ undeclared here (not in a function)
(void *) BPF_FUNC_get_stackid;
^
bpf_helpers.h:47:11: error: ‘BPF_FUNC_probe_write_user’ undeclared here (not in a function)
(void *) BPF_FUNC_probe_write_user;
^
bpf_helpers.h:49:11: error: ‘BPF_FUNC_current_task_under_cgroup’ undeclared here (not in a function)
(void *) BPF_FUNC_current_task_under_cgroup;
^
bpf_helpers.h:55:11: error: ‘BPF_FUNC_skb_get_tunnel_opt’ undeclared here (not in a function)
(void *) BPF_FUNC_skb_get_tunnel_opt;
^
bpf_helpers.h:57:11: error: ‘BPF_FUNC_skb_set_tunnel_opt’ undeclared here (not in a function)
(void *) BPF_FUNC_skb_set_tunnel_opt;
^
bpf_helpers.h:61:11: error: ‘BPF_FUNC_xdp_adjust_head’ undeclared here (not in a function)
(void *) BPF_FUNC_xdp_adjust_head;
^
bpf_helpers.h:90:11: error: ‘BPF_FUNC_skb_load_bytes’ undeclared here (not in a function)
(void *) BPF_FUNC_skb_load_bytes;
^
bpf_helpers.h:98:11: error: ‘BPF_FUNC_skb_under_cgroup’ undeclared here (not in a function)
(void *) BPF_FUNC_skb_under_cgroup;
^
bpf_helpers.h:100:11: error: ‘BPF_FUNC_skb_change_head’ undeclared here (not in a function)
(void *) BPF_FUNC_skb_change_head;
^
bpf_load.c: In function ‘load_and_attach’:
bpf_load.c:78:15: error: ‘BPF_PROG_TYPE_TRACEPOINT’ undeclared (first use in this function)
prog_type = BPF_PROG_TYPE_TRACEPOINT;
^
bpf_load.c:78:15: note: each undeclared identifier is reported only once for each function it appears in
bpf_load.c:80:15: error: ‘BPF_PROG_TYPE_XDP’ undeclared (first use in this function)
prog_type = BPF_PROG_TYPE_XDP;
^
bpf_load.c:82:15: error: ‘BPF_PROG_TYPE_PERF_EVENT’ undeclared (first use in this function)
prog_type = BPF_PROG_TYPE_PERF_EVENT;
^
bpf_load.c:84:15: error: ‘BPF_PROG_TYPE_CGROUP_SKB’ undeclared (first use in this function)
prog_type = BPF_PROG_TYPE_CGROUP_SKB;
^
bpf_load.c:86:15: error: ‘BPF_PROG_TYPE_CGROUP_SOCK’ undeclared (first use in this function)
prog_type = BPF_PROG_TYPE_CGROUP_SOCK;
^
Makefile:9: recipe for target 'bpf_load.o' failed
make[1]: *** [bpf_load.o] Error 1
make[1]: Leaving directory '/home/p4/workspace/p4c/extensions/p4c-xdp/lib'
Makefile:17: recipe for target 'bpfloader' failed
make: *** [bpfloader] Error 2

make headers_install if encountered this error

libbpf.c: In function 'bpf_create_map':
libbpf.c:29:3: error: unknown field 'map_flags' specified in initializer
.map_flags = map_flags,
^
libbpf.c:29:16: warning: excess elements in union initializer
.map_flags = map_flags,
^

xdp5.p4 and xdp6.p4: xout.drop not initialized

In xdp5.p4, initialize xoutdrop to false

control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
    bool xoutdrop = false;

but the generated xdp5.c does not initialize it, causing the following verifier error:

 R0=inv,min_value=0,max_value=0 R2=imm272,min_value=272,max_value=272 R3=imm0,min_value=0,max_value=0 R4=inv,min_value=0,max_value=0 R6=ctx R7=imm34,min_value=34,max_value=34 R8=inv56 R9=inv56 R10=fp
171: (b7) r2 = 112
172: (63) *(u32 *)(r10 -12) = r3
173: (73) *(u8 *)(r10 -16) = r1
R1 !read_ok
Makefile:54: recipe for target 'xdp5.o' failed

llvm-objdump

; xout.output_port = 0;
     172:	*(u32 *)(r10 - 12) = r3
; xout.drop = xoutdrop;
     173:	*(u8 *)(r10 - 16) = r1
; bpf_xdp_adjust_head(skb, BYTES(ebpf_packetOffsetInBits) - ebpf_outHeaderLength);
     174:	r7 -= r2
     175:	r1 = r6

Const Entries Not Supported

The following code causes a syntax error:

        const entries = { 
            (0) :  l2l3_lookup(0xAABBCCDDEEFF,0xFFEEDDCCBBAA,0xa0000001,0x0a000001);
        }  

From @mbudiu-vmw in #53 :
"There is no support for const entries yet. But please file issues for every one of these."

i40e xdp driver: the xdp program does not see vlan tag

when parsing the vlan header from XDP program, my xdp program does not see vlan tag, while tcpdump can see it. I suspect the i40e nic is doing hardware vlan offload so vlan header is kept in skb metadata. I tried disable the vlan offload but fails.

root@prmh-nsx-perf-server139:# ethtool -K enp66s0f0 rx-vlan-offload off
ethtool: bad command line argument(s)
For more information run ethtool -h

Error: either "dev" is duplicate, or "xdp" is a garbage.

Hello everyone,

We are working on P4C-XDP and XDP-BPF applications. But we have occured this error after XDP test scenario.

root@machine:~/p4c/p4c# ip link set dev ens1f0 xdp obj xdp16.o verb
Error: either "dev" is duplicate, or "xdp" is a garbage.

XDP i40e driver testing

I observed 2 issues.

  1. no xdp adjust head support
/**
 * i40e_xdp_setup - Add/remove an XDP program to a VSI
 * @vsi: the VSI to add the program
 * @prog: the XDP program
 **/
int i40e_xdp_setup(struct i40e_vsi *vsi, 
                          struct bpf_prog *prog)
{
        struct i40e_pf *pf = vsi->back;
        struct net_device *netdev = vsi->netdev;
        int i, frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
        bool need_reset;
        struct bpf_prog *old_prog;

        if (prog && prog->xdp_adjust_head)
                return -EOPNOTSUPP;
  1. When dropping packets from XDP, it still counts as rx_receive++, not rx_dropped++
    return XDP_DROP
static bool i40e_run_xdp(struct i40e_ring *rx_ring,
                         struct i40e_rx_buffer *rx_buffer,
                         union i40e_rx_desc *rx_desc,
                         unsigned int size,
                         struct bpf_prog *xdp_prog)
{
...
        case XDP_DROP:
do_drop:
                if (likely(i40e_page_is_reusable(rx_buffer->page))) {
                        i40e_reuse_rx_page(rx_ring, rx_buffer);
                        rx_ring->rx_stats.page_reuse_count++;
                        break;
                }
                dma_unmap_page(rx_ring->dev, rx_buffer->dma, PAGE_SIZE,
                               DMA_FROM_DEVICE);
                __free_pages(rx_buffer->page, 0);
                break;
        default:
                bpf_warn_invalid_xdp_action(xdp_action);
                goto do_drop;
        }

        /* clear contents of buffer_info */
        rx_buffer->page = NULL;
        return true; /* Swallowed by XDP */

return true will add packets stats to txdp_consumed_bytes

static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
{
...
                skb = i40e_fetch_rx_buffer(rx_ring, rx_desc, skb,
                                           &xdp_consumed_bytes);
                if (xdp_consumed_bytes) {
                        cleaned_count++;

                        i40e_update_rx_next_to_clean(rx_ring);

                        total_rx_bytes += xdp_consumed_bytes;
                        total_rx_packets++;

xdp6.p4: multiple fields as key

change xdp6.p4 to use 2 fields as key

    table dstmactable() {
        key = { 
                hd.ethernet.protocol : exact;
                hd.ipv4.dstAddr : exact;
              }
        actions = { 

got compile error

clang \
	-D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
	-Wno-compare-distinct-pointer-types \
	-Wno-gnu-variable-sized-type-not-at-end \
	-Wno-tautological-compare \
	-O2 -emit-llvm -g -c xdp6.c -o -| llc -march=bpf -filetype=obj -o xdp6.o
In file included from xdp6.c:3:
./xdp6.h:57:9: error: duplicate member 'field0'
    u32 field0; /* hd.ipv4.dstAddrexact */
        ^
./xdp6.h:56:9: note: previous declaration is here
    u16 field0; /* hd.ethernet.protocolexact */
        ^

patch with the following

--- a/backends/ebpf/ebpfTable.cpp
+++ b/backends/ebpf/ebpfTable.cpp
@@ -97,6 +97,7 @@ void EBPFTable::emitKeyType(CodeBuilder* builder) {
         auto matchType = mtdecl->getNode()->to<IR::Declaration_ID>();
         if (matchType->name.name != P4::P4CoreLibrary::instance.exactMatch.name)
             ::error("Match of type %1% not supported", c->matchType);
+               fieldNumber++;
     }
 
     builder->blockEnd(false);
@@ -270,6 +271,7 @@ void EBPFTable::emitKey(CodeBuilder* builder, cstring keyName) {
             codeGen->visit(c->expression);
         }
         builder->endOfStatement(true);
+               fieldNumber++;
     }
 }

xdp14: action_md need to initialize to zero

when compiling

gcc -I../lib/ ../lib//libbpf.o ../lib//bpf_load.o load_and_verify.c -lelf -o bpfloader
../p4c-xdp -I ../p4include --target xdp -o xdp14.c xdp14.p4;
xdp14.p4(90): warning: action_md.output.port may be uninitialized
        outport = action_md.output.port;
                  ^^^^^^^^^^^^^^^^^^^^^
...
verifier error
56: (5d) if r1 != r4 goto pc+1
 R0=map_value(ks=4,vs=36,id=0),min_value=0,max_value=0 R1=imm1,min_value=0,max_value=0 R3=imm1,min_value=1,max_value=1 R4=imm0,min_value=0,max_value=0 R5=imm0,min_value=0,max_value=0 R6=ctx R7=imm38,min_value=38,max_value=38 R8=imm0,min_value=0,max_value=0 R10=fp
57: (bf) r5 = r2
R2 !read_ok

Fix it with

    accept:
    {
        u8 hit;
        u32 outport;
        u32 bitmap;
-        struct action_md_t action_md;
+        struct action_md_t action_md = {};
        enum xdp_action xact;
        u32 tmp_5;
        u8 tmp_6;
        u32 tmp_7;
        u8 tmp_8;
        u32 tmp_9;
        u8 tmp_10;
        {
            outport = 0;
            bitmap = 0;
            xact = XDP_PASS;
            /* action_bitmap.apply()*/
            {

Error fetching ELF ancillary data!

Hello,

When doing a make in the test directory I got an error from the xdp7 example, which is already referenced here: #22
But then when I try to load any other program I get this error:

% sudo ip link set dev eno1 xdp obj xdp1.o
0 maps not supported in current map section!
Error fixing up map structure, incompatible struct bpf_elf_map used?
Error fetching ELF ancillary data!

I followed your README to install and setup everything and then I tried running this XDP code:

#include <linux/bpf.h>

#ifndef __section
# define __section(NAME)                  \
   __attribute__((section(NAME), used))
#endif

__section("prog")
int xdp_drop(struct xdp_md *ctx) {
    return XDP_DROP;
}
char __license[] __section("license") = "GPL";

This code works well so I guess it's not an issue about the installation of the tool but more like an issue on the configuration of my system ?

Thanks in advance

setValid()/isValid()/setInvalid() inside action block

Using setValid()/isValid()/setInvalid() inside action block create issues on output c code.

for example:

action forward_port(bit<32> egress_port){
        xout.output_port = egress_port;
        if (hdr.geneve.isValid()){
            hdr.out_ethernet.setInvalid();
            hdr.out_ip.setInvalid();
            hdr.out_udp.setInvalid();
            hdr.geneve.setInvalid();
        }
    }

would produce

 case forward_port:
                        {
xout.output_port = value->u.forward_port.egress_port;if (hdr.geneve.isValid()) {
hdr.out_ethernet.setInvalid();hdr.out_ip.setInvalid();hdr.out_udp.setInvalid();hdr.geneve.setInvalid();                            }                        }
                        break;

which does not work. It should test isValid() by testing ebpf_valid bit instead of calling isValid(), similar issue with setValid() and setInvalid().

These work fine inside "apply" block.

the docker image seems out of date

I use vagrant to download the Ubuntu and run the below command :

# docker images

the output is

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
u9012063/p4xdp      latest              975d533176d4        2 years ago         2.66GB

And then I run the docker image and found there are lots of diffrences between the docker and the git repo.
So for now , I must compile the p4c and extend the compiler using the bash command? And it seems there are some header including problems when I run the make in the ~/p4c/extensions/p4c-xdp/tests

xdp11.p4: swap ether src dst, return XDP_TX

try to mimic the same behavior as sample/bpf/xdp2_kern.c
which swaps the ether src and dst, then output to the same port
It works ok, however, there is no way to return XDP_TX

currently depends on xout.drop then return XDP_DROP or XDP_PASS
XDP_TX tells the driver to send the packet to the same port as receiving.
should we allow P4 programmer to say "return XDP_TX" ?

Docker Image Out of Date

The easiest way to test was to use the docker image provided. I'm trying to do tests on XDP again but the docker image seems to be out of date and I couldn't get it to rebuild in old image after git pull in p4c and p4c-xdp directories.
I did:

apt-get update
apt-get install cmake
cmake .. (in build dir)

Output was the following:

CMake Warning at backends/bmv2/CMakeLists.txt:125 (MESSAGE):
  BMv2 simple switch is not available, not adding BMv2 tests


-- Added 9 tests to 'ebpf' (0 xfails)
-- Added 486 tests to 'p4' (1 xfails)
-- Added 177 tests to 'p14_to_16' (0 xfails)
-- CTest parallel: -j 8
-- Configuring incomplete, errors occurred!
See also "/home/p4c/build/CMakeFiles/CMakeOutput.log".
See also "/home/p4c/build/CMakeFiles/CMakeError.log".

FWIW the last few lines of CMakeError.log are as follows:

Determining if the function pthread_create exists in the pthreads failed with the following output:
Change Dir: /home/p4c/build/CMakeFiles/CMakeTmp

Run Build Command:"/usr/bin/make" "cmTC_7e0ae/fast"
/usr/bin/make -f CMakeFiles/cmTC_7e0ae.dir/build.make CMakeFiles/cmTC_7e0ae.dir/build
make[1]: Entering directory '/home/p4c/build/CMakeFiles/CMakeTmp'
Building C object CMakeFiles/cmTC_7e0ae.dir/CheckFunctionExists.c.o
/usr/bin/cc    -DCHECK_FUNCTION_EXISTS=pthread_create   -o CMakeFiles/cmTC_7e0ae.dir/CheckFunctionExists.c.o   -c /usr/share/cmake-3.7/Modules/CheckFunctionExists.c
Linking C executable cmTC_7e0ae
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_7e0ae.dir/link.txt --verbose=1
/usr/bin/cc   -DCHECK_FUNCTION_EXISTS=pthread_create    CMakeFiles/cmTC_7e0ae.dir/CheckFunctionExists.c.o  -o cmTC_7e0ae -rdynamic -lpthreads 
/usr/bin/ld: cannot find -lpthreads
collect2: error: ld returned 1 exit status
CMakeFiles/cmTC_7e0ae.dir/build.make:97: recipe for target 'cmTC_7e0ae' failed
make[1]: *** [cmTC_7e0ae] Error 1
make[1]: Leaving directory '/home/p4c/build/CMakeFiles/CMakeTmp'
Makefile:126: recipe for target 'cmTC_7e0ae/fast' failed
make: *** [cmTC_7e0ae/fast] Error 2

BPF spills register with 1 byte value to use 8 byte on stack

I still have no idea why such a simple program will spill the 1 byte value to use 8 byte on stack.

#include "xdp_model.p4"
header Ethernet {
    bit<48> source;
}
struct Headers {
    Ethernet ethernet;
}
parser Parser(packet_in packet, out Headers hd) {
    state start {
        packet.extract(hd.ethernet);
        transition accept;
    }
}
control Ingress(inout Headers hdr, in xdp_input xin, out xdp_output xout) {
    apply {
        xout.output_port = 0;
        xout.output_action = xdp_action.XDP_PASS;
    }
}
control Deparser(in Headers hdrs, packet_out packet) {
    apply {
        packet.emit(hdrs.ethernet);
    }
}
xdp(Parser(), Ingress(), Deparser()) main;

then I greatly reduce a lot of stuff, to this very simple C code.

#include "xdp1.h"
#define KBUILD_MODNAME "xdptest"
#include <linux/bpf.h>
#include "bpf_helpers.h"

#define load_byte(data, b)  (*((u8*)(data) + (b)))
#define htonl
#define htons

#define EBPF_MASK(t, w) ((((t)(1)) << (w)) - (t)1)
#define write_byte(base, offset, v)  *(u8*)(((u8*)base) + (offset)) = v 

struct bpf_map_def SEC("maps") ebpf_outTable = {
    .type = BPF_MAP_TYPE_PERCPU_ARRAY,
    .key_size = sizeof(u32),
    .value_size = sizeof(u32),
    .pinning = 2, /* PIN_GLOBAL_NS */
    .max_entries = 1 /* No multicast support */
};

SEC("prog")
int ebpf_filter(struct xdp_md* skb){
    u8 ebpf_byte;
    u32 ebpf_zero = 0;
    u32 ebpf_outHeaderLength = 0;
    struct xdp_output xout;
    /* TODO: this should be initialized by the environment. HOW? */
    struct xdp_input xin;
    struct Headers hd = {};

    void* pktstart = ((u8*)(long)skb->data);
    void* ebpf_packetEnd = ((u8*)(long)skb->data_end);
    
        /* extract(hd.ethernet)*/
        if (ebpf_packetEnd < pktstart + 14) {
            return XDP_ABORTED;
        }
            xout.output_port = 0;
            xout.output_action = XDP_PASS;
        hd.ethernet.source[0] = ((load_byte(pktstart, 0) ));
        hd.ethernet.source[1] = ((load_byte(pktstart, 1) ));
        hd.ethernet.source[2] = ((load_byte(pktstart, 2) ));
        hd.ethernet.source[3] = ((load_byte(pktstart, 3) ));
        hd.ethernet.source[4] = ((load_byte(pktstart, 4) ));
        hd.ethernet.source[5] = ((load_byte(pktstart, 5) ));

        hd.ethernet.ebpf_valid = 1;

    /* deparser */
        if (hd.ethernet.ebpf_valid) ebpf_outHeaderLength += 48;
        
        bpf_xdp_adjust_head(skb, 14 - ebpf_outHeaderLength);
        pktstart = ((u8*)(long)skb->data);
        ebpf_packetEnd = ((u8*)(long)skb->data_end);
        
            /* packet.emit(hd.ethernet)*/
            if (hd.ethernet.ebpf_valid) {
                if (ebpf_packetEnd < pktstart + 14) {
                    return XDP_ABORTED;
                }
                ebpf_byte = hd.ethernet.source[0];
                write_byte(pktstart, 0, (ebpf_byte));
                ebpf_byte = hd.ethernet.source[1];
                write_byte(pktstart, 1, (ebpf_byte));
                ebpf_byte = hd.ethernet.source[2];
                write_byte(pktstart, 2, (ebpf_byte));
                ebpf_byte = hd.ethernet.source[3];
                write_byte(pktstart, 3, (ebpf_byte));
                ebpf_byte = hd.ethernet.source[4];
                write_byte(pktstart, 4, (ebpf_byte));
                ebpf_byte = hd.ethernet.source[5];
                write_byte(pktstart, 5, (ebpf_byte));
            }

    bpf_map_update_elem(&ebpf_outTable, &ebpf_zero, &xout.output_port, BPF_ANY);
    return xout.output_action;
}
char _license[] SEC("license") = "GPL";

Still the objdump shows usage of 8byte on stack

Disassembly of section prog:
ebpf_filter:
; int ebpf_filter(struct xdp_md* skb){
       0:	r7 = r1
       1:	r6 = 0
; u32 ebpf_zero = 0;
       2:	*(u32 *)(r10 - 4) = r6
; void* ebpf_packetEnd = ((u8*)(long)skb->data_end);
       3:	r2 = *(u32 *)(r7 + 4)
; void* pktstart = ((u8*)(long)skb->data);
       4:	r1 = *(u32 *)(r7 + 0)
; if (ebpf_packetEnd < pktstart + 14) {
       5:	r3 = r1
       6:	r3 += 14
       7:	if r3 > r2 goto 40
       8:	r2 = 2
; xout.output_action = XDP_PASS;
       9:	*(u64 *)(r10 - 16) = r2
; hd.ethernet.source[5] = ((load_byte(pktstart, 5) ));
      10:	r2 = *(u8 *)(r1 + 5)
; hd.ethernet.source[4] = ((load_byte(pktstart, 4) ));
      11:	*(u64 *)(r10 - 24) = r2
      12:	r2 = *(u8 *)(r1 + 4)
; hd.ethernet.source[3] = ((load_byte(pktstart, 3) ));
      13:	*(u64 *)(r10 - 32) = r2
      14:	r2 = *(u8 *)(r1 + 3)
; hd.ethernet.source[2] = ((load_byte(pktstart, 2) ));
      15:	*(u64 *)(r10 - 40) = r2
      16:	r2 = *(u8 *)(r1 + 2)
; hd.ethernet.source[1] = ((load_byte(pktstart, 1) ));
      17:	*(u64 *)(r10 - 48) = r2
      18:	r8 = *(u8 *)(r1 + 1)

what I'm hoping to see is s.t like this, with r10 - off, off is diff by 1

; *(u8 *)data = (u8) hds.eth.fields[i]; 
      10:	r7 = *(u8 *)(r6 + 0)
; hds.eth.fields[i] = (u8)(load_byte(data,  BYTES(i*8)) >> 0);
      11:	*(u8 *)(r10 - 14) = r7
      12:	r2 = *(u8 *)(r6 + 1)
      13:	*(u8 *)(r10 - 13) = r2
      14:	r2 = *(u8 *)(r6 + 2)
      15:	*(u8 *)(r10 - 12) = r2
      16:	r2 = *(u8 *)(r6 + 3)
      17:	*(u8 *)(r10 - 11) = r2
      18:	r2 = *(u8 *)(r6 + 4)
      19:	*(u8 *)(r10 - 10) = r2
      20:	r2 = *(u8 *)(r6 + 5)
      21:	*(u8 *)(r10 - 9) = r2

Missing table key fields inside header file

A table with 6 keys:

    table flow_table {
      key = {
        hdr.out_ip.srcAddr : exact;
        hdr.out_ip.dstAddr : exact;
        hdr.out_ethernet.source : exact;
        hdr.out_ethernet.destination : exact;
        flow_dst_port : exact;
        flow_src_port : exact;
      }
      actions = {
        encap;
        NoAction;
      }
      default_action = NoAction;
      implementation = hash_table(128);
    }

produced C code in header file:

struct flow_table_key {
    u8 field2[6]; /* hdr.out_ethernet.source */
    u32 field0; /* hdr.out_ip.srcAddr */
    u16 field4; /* flow_dst_port */
};
enum flow_table_actions {
    encap,
    NoAction,
};
struct flow_table_value {
    enum flow_table_actions action;
    union {
        struct {
            u8 srcMac[6];
            u8 dstMac[6];
            u32 srcIP;
            u32 dstIP;
        } encap;
        struct {
        } NoAction;
    } u;
};

field1, field3 and field5 are missing, but they are referenced inside c file

                    /* construct key */
                    struct flow_table_key key = {};
                    key.field0 = hdr.out_ip.srcAddr;
                    key.field1 = hdr.out_ip.dstAddr;
                    memcpy(&key.field2, &hdr.out_ethernet.source, 6);
                    memcpy(&key.field3, &hdr.out_ethernet.destination, 6);
                    key.field4 = flow_dst_port;
                    key.field5 = flow_src_port;

hence the compiler error by clang

geneve.c:439:25: error: no member named 'field1' in 'struct flow_table_key'
                    key.field1 = hdr.out_ip.dstAddr;
                    ~~~ ^
geneve.c:441:33: error: no member named 'field3' in 'struct flow_table_key'
                    memcpy(&key.field3, &hdr.out_ethernet.destination, 6);
                            ~~~ ^
geneve.c:443:25: error: no member named 'field5' in 'struct flow_table_key'
                    key.field5 = flow_src_port;
                    ~~~ ^
3 errors generated.

dword issue in .h file

Hello,
When we compile the .p4 file using p4c-xdp, it generates a .h and .c file. The .h file is missing a macro for dword, which needs to be inserted manually. Can you please fix this?

Thank you,
Sincerely,

Error compiling control-plane user_xdp5.h

Hi,
When I run the below command in the /p4c/extensions/p4c-xdp/tests :

# gcc -I ../lib/   ../lib/libbpf.o user_xdp5.c -o xdp5

there's an error that

In file included from xdp5.h:6:0,
                 from user_xdp5.c:20:
ebpf_xdp.h:24:25: fatal error: ebpf_kernel.h: No such file or directory
 #include "ebpf_kernel.h"
                         ^
compilation terminated.

And then I found the header files to be included are in the /p4c/backends/ebpf/runtime/,
so I move the ebpf_kernel.h and ebpf_common.h into the /tests :

root@debian:~/p4c/extensions/p4c-xdp/tests# cp /root/p4c/backends/ebpf/runtime/ebpf_common.h ./
root@debian:~/p4c/extensions/p4c-xdp/tests# cp /root/p4c/backends/ebpf/runtime/ebpf_kernel.h ./

however, when I compile again , some other errors occured :

In file included from ebpf_xdp.h:24:0,
                 from xdp5.h:6,
                 from user_xdp5.c:20:
ebpf_kernel.h:111:19: error: static declaration of ‘bpf_lookup_elem’ follows non-static declaration
 static inline int bpf_lookup_elem(int fd, void *key, void *value) {
                   ^~~~~~~~~~~~~~~
In file included from user_xdp5.c:17:0:
../lib/libbpf.h:10:5: note: previous declaration of ‘bpf_lookup_elem’ was here
 int bpf_lookup_elem(int fd, void *key, void *value);
     ^~~~~~~~~~~~~~~
In file included from ebpf_xdp.h:24:0,
                 from xdp5.h:6,
                 from user_xdp5.c:20:
ebpf_kernel.h:131:19: error: static declaration of ‘bpf_update_elem’ follows non-static declaration
 static inline int bpf_update_elem(int fd, void *key, void *value, u64 flags) {
                   ^~~~~~~~~~~~~~~
In file included from user_xdp5.c:17:0:
../lib/libbpf.h:9:5: note: previous declaration of ‘bpf_update_elem’ was here
 int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
     ^~~~~~~~~~~~~~~
In file included from ebpf_xdp.h:24:0,
                 from xdp5.h:6,
                 from user_xdp5.c:20:
ebpf_kernel.h:149:19: error: static declaration of ‘bpf_delete_elem’ follows non-static declaration
 static inline int bpf_delete_elem(int fd, void *key) {
                   ^~~~~~~~~~~~~~~
In file included from user_xdp5.c:17:0:
../lib/libbpf.h:11:5: note: previous declaration of ‘bpf_delete_elem’ was here
 int bpf_delete_elem(int fd, void *key);
     ^~~~~~~~~~~~~~~
In file included from ebpf_xdp.h:24:0,
                 from xdp5.h:6,
                 from user_xdp5.c:20:
ebpf_kernel.h:165:19: error: static declaration of ‘bpf_obj_pin’ follows non-static declaration
 static inline int bpf_obj_pin(int fd, const char *pathname) {
                   ^~~~~~~~~~~
In file included from user_xdp5.c:17:0:
../lib/libbpf.h:18:5: note: previous declaration of ‘bpf_obj_pin’ was here
 int bpf_obj_pin(int fd, const char *pathname);
     ^~~~~~~~~~~
In file included from ebpf_xdp.h:24:0,
                 from xdp5.h:6,
                 from user_xdp5.c:20:
ebpf_kernel.h:181:19: error: static declaration of ‘bpf_obj_get’ follows non-static declaration
 static inline int bpf_obj_get(const char *pathname) {
                   ^~~~~~~~~~~
In file included from user_xdp5.c:17:0:
../lib/libbpf.h:19:5: note: previous declaration of ‘bpf_obj_get’ was here
 int bpf_obj_get(const char *pathname);
     ^~~~~~~~~~~
user_xdp5.c: In function ‘main’:
user_xdp5.c:29:25: error: storage size of ‘key’ isn’t known
  struct dstmactable_key key;
                         ^~~
user_xdp5.c:30:27: error: storage size of ‘value’ isn’t known
  struct dstmactable_value value;
                           ^~~~~
user_xdp5.c:33:2: warning: implicit declaration of function ‘initialize_tables’ [-Wimplicit-function-declaration]
  initialize_tables();
  ^~~~~~~~~~~~~~~~~
user_xdp5.c:35:17: error: ‘Fallback_action’ undeclared (first use in this function)
  value.action = Fallback_action;
                 ^~~~~~~~~~~~~~~
user_xdp5.c:35:17: note: each undeclared identifier is reported only once for each function it appears in

could you give me some advice?
Thanks.

verifier: xdp7.p4 hit the kernel max BPF stack size

xdp7.p4 show the error message

394: (05) goto pc+56
451: (7b) *(u64 *)(r10 -528) = r0
invalid stack off=-528 size=8

looking at the source code

    } else if (reg->type == FRAME_PTR || reg->type == PTR_TO_STACK) {
        if (off >= 0 || off < -MAX_BPF_STACK) {
            verbose("invalid stack off=%d size=%d\n", off, size);
            return -EACCES;
        }

we only allow stack size of 512 + 32 + 8

#define MAX_BPF_STACK (512 /* from filter.h */ + \
    32 /* space for rbx,r13,r14,r15 */ + \
    8 /* space for skb_copy_bits */)

need to discuss with kernel bpf maintainer...

p4c-xdp: treat warning as error

not urgent at all but is there a way to treat warning as error, so the shell returns non-zero?
for example:

# make
 ../p4c-xdp -I ../p4include --target xdp -o xdp14.c xdp14.p4;
xdp14.p4(90): warning: action_md.output.port may be uninitialized
        outport = action_md.output.port;

I want the "make" stops when seeing this warning. So that the travis-ci could report build failed.

workaround for hitting BPF max stack size

I declare another "struct Headers hd__" at the deparser code block, so that the live range of "hd" is reset at deparser.

An example of using xdp7.p4, before the patch, we use 616 byte stack memory

# llvm-objdump -S -no-show-raw-insn xdp7.o | grep "r10 -" | awk '{print $7}' | sort -n
616
After the patch:
392

What do you think?

index db5fff7..433d546 100644
--- a/tests/xdp7.c
+++ b/root/xdp7.c
@@ -1,4 +1,4 @@
-/* Automatically generated by p4c-xdp from xdp7.p4 on Thu Mar  2 08:04:24 2017
+/* Automatically generated by p4c-xdp from xdp7.p4 on Wed Mar  1 09:52:18 2017
  */
 #include "xdp7.h"
 #define KBUILD_MODNAME "xdptest"
@@ -133,6 +133,7 @@ int ebpf_filter(struct xdp_md* skb){
             .ebpf_valid = 0
         },
     };
+    struct Headers hd__;
     unsigned ebpf_packetOffsetInBits = 0;
     enum ebpf_errorCodes ebpf_errorCode = NoError;
     void* ebpf_packetStart = ((void*)(long)skb->data);
@@ -379,12 +380,13 @@ int ebpf_filter(struct xdp_md* skb){
     }
     /* deparser */
     {
+        hd__ = hd;
         {
-            if (hd.ethernet.ebpf_valid) ebpf_outHeaderLength += 112;
-            if (hd.ipv4.ebpf_valid) ebpf_outHeaderLength += 160;
-            if (hd.icmp.ebpf_valid) ebpf_outHeaderLength += 32;
-            if (hd.udp.ebpf_valid) ebpf_outHeaderLength += 64;
-            if (hd.tcp.ebpf_valid) ebpf_outHeaderLength += 160;
+            if (hd__.ethernet.ebpf_valid) ebpf_outHeaderLength += 112;
+            if (hd__.ipv4.ebpf_valid) ebpf_outHeaderLength += 160;
+            if (hd__.icmp.ebpf_valid) ebpf_outHeaderLength += 32;
+            if (hd__.udp.ebpf_valid) ebpf_outHeaderLength += 64;
+            if (hd__.tcp.ebpf_valid) ebpf_outHeaderLength += 160;
         }
         bpf_xdp_adjust_head(skb, BYTES(ebpf_packetOffsetInBits) - BYTES(ebpf_outHeaderLength));
         ebpf_packetStart = ((void*)(long)skb->data);
@@ -392,230 +394,230 @@ int ebpf_filter(struct xdp_md* skb){
         ebpf_packetOffsetInBits = 0;
         u8 hit_0;
         {
-            /* packet.emit(hd.ethernet)*/
-            if (hd.ethernet.ebpf_valid) {
+            /* packet.emit(hd__.ethernet)*/
+            if (hd__.ethernet.ebpf_valid) {
                 if (ebpf_packetEnd < ebpf_packetStart + BYTES(ebpf_packetOffsetInBits + 112)) {
                     ebpf_errorCode = PacketTooShort;
                     return XDP_ABORTED;
                 }
-                ebpf_byte = ((char*)(&hd.ethernet.destination))[0];
+                ebpf_byte = ((char*)(&hd__.ethernet.destination))[0];
                 write_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 0, (ebpf_byte) << 0);
-                ebpf_byte = ((char*)(&hd.ethernet.destination))[1];
+                ebpf_byte = ((char*)(&hd__.ethernet.destination))[1];
                 write_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 1, (ebpf_byte) << 0);
-                ebpf_byte = ((char*)(&hd.ethernet.destination))[2];
+                ebpf_byte = ((char*)(&hd__.ethernet.destination))[2];
                 write_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 2, (ebpf_byte) << 0);
-                ebpf_byte = ((char*)(&hd.ethernet.destination))[3];
+                ebpf_byte = ((char*)(&hd__.ethernet.destination))[3];
                 write_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 3, (ebpf_byte) << 0);
-                ebpf_byte = ((char*)(&hd.ethernet.destination))[4];
+                ebpf_byte = ((char*)(&hd__.ethernet.destination))[4];
                 write_byte(ebpf_packetStart, BYTES(ebpf_packetOffsetInBits) + 4, (ebpf_byte) << 0);
-                ebpf_byte = ((char*)(&hd.ethernet.destination))[5];
+                ebpf_byte = ((char*)(&hd__.ethernet.destination))[5];
... <skip the rest>

CMake cannot handle some setups

My setup is:

git/p4c
git/p4c-xdp
git/p4c/extensions/p4c-xdp -> symlink to ../../p4c-xdp

When I type cmake .. in the build directory of p4c I get this:

CMake Error at cmake/P4CUtils.cmake:86 (file):
  file failed to open for writing (Not a directory):

    /home/mbudiu/git/p4c/build/xdp/../p4c-xdp/tests/xdp15.p4.test
Call Stack (most recent call first):
  cmake/P4CUtils.cmake:136 (p4c_add_test_with_args)
  cmake/P4CUtils.cmake:180 (p4c_add_test_list)
  extensions/p4c-xdp/CMakeLists.txt:60 (p4c_add_tests)

docker unable to setrlimit

even when I run docker with
docker run -u root

../p4c-xdp -I ../p4include --target xdp -o xdp16.c xdp16.p4;
clang \
	-D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
	-Wno-compare-distinct-pointer-types \
	-Wno-gnu-variable-sized-type-not-at-end \
	-Wno-tautological-compare \
	-O2 -emit-llvm -g -c xdp16.c -o -| llc -march=bpf -filetype=obj -o xdp16.o
sudo ./bpfloader xdp16.o || true
setrlimit(RLIMIT_MEMLOCK, RLIM_INFINITY): Operation not permitted

Can't set 48 bit field in header

Trying to set 48 bit fields fields causes an error as shown below. Setting 32 bit fields does work.

It seems like the function memcpy tries to use the value to which the field must be set as an address:
18838586676582 = 0x112233445566 (the value to which the MAC address should be set)
memcpy(&hd.outer_eth.destination, &18838586676582, 6);

For some reason I also can't use setValid(); inside an action. When using it directly inside the apply{} block it works.

P4 Code:

action l2l3_lookup(macAddr_t dmac, macAddr_t smac, ipAddr_t dip, ipAddr_t sip) {
        hd.outer_eth.destination = dmac;
        hd.outer_eth.source = smac;

        hd.outer_ipv4.dstAddr = dip;
        hd.outer_ipv4.srcAddr = sip;
    }

Errors:

p4c-xdp --Werror -I ../p4include --target xdp -o xdp_vlan_to_vxlan.c xdp_vlan_to_vxlan.p4;
clang \
	-D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
	-Wno-compare-distinct-pointer-types \
	-Wno-gnu-variable-sized-type-not-at-end \
	-Wno-tautological-compare \
	-O2 -emit-llvm -g -c xdp_vlan_to_vxlan.c -o -| llc -march=bpf -filetype=obj -o xdp_vlan_to_vxlan.o
xdp_vlan_to_vxlan.c:213:43: error: no member named 'setValid' in 'struct ipv4_t'
                            hd.outer_ipv4.setValid();
                            ~~~~~~~~~~~~~ ^
xdp_vlan_to_vxlan.c:233:47: error: cannot take the address of an rvalue of type
      'long'
            memcpy(&hd.outer_eth.destination, &18838586676582, 6);
                                              ^~~~~~~~~~~~~~~
xdp_vlan_to_vxlan.c:234:42: error: cannot take the address of an rvalue of type
      'long'
            memcpy(&hd.outer_eth.source, &37603585123959, 6);
                                         ^~~~~~~~~~~~~~~
3 errors generated.
sudo ./bpfloader xdp_vlan_to_vxlan.o || true

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.