├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── AUTHORS
├── CMakeLists.txt
├── Dockerfile
├── LICENSE
├── README.md
├── Vagrantfile
├── compile-bpf.sh
├── doc
├── images
│ └── p4xdp-workflow.png
├── lpc18.pdf
├── lpc18
│ ├── .gitignore
│ ├── Makefile
│ ├── acmart.cls
│ ├── architecture.pdf
│ ├── background.tex
│ ├── compilation.tex
│ ├── conclusions.tex
│ ├── introduction.tex
│ ├── kernel_test.png
│ ├── p4cxdp-lpc18.pdf
│ ├── results.tex
│ ├── stf.pdf
│ ├── stf.vsdx
│ ├── testing.tex
│ ├── testing_workflow.pdf
│ ├── testing_workflow.vsdx
│ ├── titlesec.sty
│ ├── top.bib
│ ├── top.tex
│ └── user_test.png
├── p4c-xdp-lpc18-presentation.pdf
├── p4xdp-iovisor17.pdf
└── perf.txt
├── lib
├── COPYING
├── Makefile
├── bpf_helpers.h
├── bpf_load.c
├── bpf_load.h
├── libbpf.c
└── libbpf.h
├── ovs-parse-14.p4
├── ovs.c
├── ovs.p4
├── p4c-xdp.cpp
├── p4include
└── xdp_model.p4
├── run-bpf.sh
├── run-p4c-xdp.sh
├── target.cpp
├── target.h
├── test_ebpf_map.c
├── tests
├── Makefile
├── README.md
├── ebpf_headers.p4
├── ebpf_xdp.h
├── empty.stf
├── load_and_verify.c
├── user_xdp10.c
├── user_xdp5.c
├── xdp.p4
├── xdp.stf
├── xdp1.p4
├── xdp1.stf
├── xdp10.p4
├── xdp11.p4
├── xdp12.p4
├── xdp13.p4
├── xdp14.p4
├── xdp15.p4
├── xdp16.p4
├── xdp17.p4
├── xdp2.p4
├── xdp2.stf
├── xdp3.p4
├── xdp4.p4
├── xdp5.p4
├── xdp6.p4
├── xdp7.p4
├── xdp8.p4
└── xdp9.p4
├── tools
└── install_dependencies.sh
├── xdpBackend.cpp
├── xdpBackend.h
├── xdpControl.cpp
├── xdpControl.h
├── xdpModel.cpp
├── xdpModel.h
├── xdpProgram.cpp
├── xdpProgram.h
└── xdp_target.py
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 | on:
3 | push:
4 | branches: [ master ]
5 | pull_request:
6 | branches: [ master ]
7 | schedule:
8 | - cron: "0 13 * * 1"
9 | jobs:
10 | test:
11 | runs-on: ubuntu-20.04
12 | steps:
13 | - uses: actions/checkout@v1
14 | - name: ccache
15 | uses: hendrikmuhs/ccache-action@v1
16 | with:
17 | key: ${{ matrix.os }}
18 | max-size: 1000M
19 | - name: Install P4C dependencies
20 | run: |
21 | git clone https://github.com/p4lang/p4c $GITHUB_WORKSPACE/../p4c
22 | cd $GITHUB_WORKSPACE/../p4c
23 | git submodule update --init --recursive
24 | cd $GITHUB_WORKSPACE
25 | ./tools/install_dependencies.sh
26 | - name: Prepare P4C
27 | run: |
28 | mkdir -p $GITHUB_WORKSPACE/../p4c/extensions/
29 | cp -r $GITHUB_WORKSPACE $GITHUB_WORKSPACE/../p4c/extensions/p4c-xdp
30 | ln -sf $GITHUB_WORKSPACE $GITHUB_WORKSPACE/../p4c/extensions/p4c-xdp
31 | cd $GITHUB_WORKSPACE/../p4c
32 | python3 backends/ebpf/build_libbpf
33 | mkdir $GITHUB_WORKSPACE/../p4c/build
34 | cd $GITHUB_WORKSPACE/../p4c/build
35 | cmake .. -DCMAKE_RUN_CLANG_TIDY=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
36 | - name: Install P4C with the xdp extension
37 | run: |
38 | cd $GITHUB_WORKSPACE/../p4c/build
39 | make -j2
40 | - name: Test the xdp extension
41 | run: |
42 | cd $GITHUB_WORKSPACE/../p4c/build
43 | sudo -E ctest -R xdp --output-on-failure --schedule-random
44 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib/*.o
2 | tests/*.c
3 | tests/*.h
4 | tests/*.o
5 | tests/bpfloader
6 | p4c-xdp
7 |
8 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | =============================== ===============================================
2 | Name Email
3 | =============================== ===============================================
4 | Mihai Budiu mbudiu@vmware.com
5 | William Tu u9012063@gmail.com
6 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # CMakefile for the XDP P4-16 back-end.
2 |
3 | message(STATUS "Start configuring XDP back end")
4 |
5 | set (P4C_XDP_SOURCES
6 | p4c-xdp.cpp
7 | xdpModel.cpp
8 | xdpControl.cpp
9 | xdpProgram.cpp
10 | target.cpp
11 | xdpBackend.cpp
12 | ../../backends/ebpf/ebpfProgram.cpp
13 | ../../backends/ebpf/ebpfOptions.cpp
14 | ../../backends/ebpf/ebpfTable.cpp
15 | ../../backends/ebpf/ebpfControl.cpp
16 | ../../backends/ebpf/ebpfParser.cpp
17 | ../../backends/ebpf/target.cpp
18 | ../../backends/ebpf/ebpfType.cpp
19 | ../../backends/ebpf/codeGen.cpp
20 | ../../backends/ebpf/ebpfModel.cpp
21 | ../../backends/ebpf/midend.cpp
22 | ../../backends/ebpf/lower.cpp
23 | )
24 |
25 | set (P4C_XDP_HEADERS
26 | xdpModel.h
27 | xdpProgram.h
28 | xdpControl.h
29 | target.h
30 | xdpBackend.h
31 | )
32 |
33 | set (XDP_DIST_HEADERS p4include/xdp_model.p4)
34 |
35 | add_cpplint_FILES(${CMAKE_CURRENT_SOURCE_DIR} "${P4C_XDP_SOURCES};${P4C_XDP_HEADERS}")
36 |
37 | build_unified(P4C_XDP_SOURCES)
38 |
39 | add_executable(p4c-xdp ${P4C_XDP_SOURCES})
40 | target_link_libraries(p4c-xdp ${P4C_LIBRARIES} ${P4C_LIB_DEPS})
41 |
42 | install (TARGETS p4c-xdp
43 | RUNTIME DESTINATION ${P4C_RUNTIME_OUTPUT_DIRECTORY})
44 | install (DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/p4include
45 | DESTINATION ${P4C_ARTIFACTS_OUTPUT_DIRECTORY})
46 |
47 | add_custom_target(linkp4cxdp
48 | COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/p4c-xdp ${P4C_BINARY_DIR}/p4c-xdp
49 | COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include &&
50 | ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${XDP_DIST_HEADERS} ${P4C_BINARY_DIR}/p4include
51 | COMMAND ${CMAKE_COMMAND} -E create_symlink ${P4C_BINARY_DIR}/p4include ${CMAKE_CURRENT_BINARY_DIR}/p4include
52 | )
53 |
54 | # check for the libbpf library, it is required for p4c-xdp to work
55 | find_library(LIBBPF_XDP NAMES bpf HINTS "${P4C_SOURCE_DIR}/backends/ebpf/runtime/usr/lib64/")
56 | if (LIBBPF_XDP)
57 | message(STATUS "Found libbpf library")
58 | else()
59 | message(FATAL_ERROR "Missing the libbpf dependency, disabling kernel tests."
60 | " You can install libbpf by running './build_libbpf' in the "
61 | "$${P4C_SOURCE_DIR}/backends/ebpf/runtime folder.")
62 | endif()
63 |
64 | # Automatically insert the xdp_target in the targets folder
65 | if(CMAKE_HOST_UNIX)
66 | EXECUTE_PROCESS(COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/xdp_target.py ${P4C_SOURCE_DIR}/backends/ebpf/targets/xdp_target.py
67 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
68 | )
69 | endif(CMAKE_HOST_UNIX)
70 |
71 | set (XFAIL_TESTS_XDP)
72 |
73 | add_dependencies(p4c_driver linkp4cxdp)
74 |
75 | set(XDP_DRIVER "${P4C_SOURCE_DIR}/backends/ebpf/run-ebpf-test.py -t xdp -c \"${P4C_BINARY_DIR}/p4c-xdp\"")
76 |
77 | # This file will not run the full tests, but it will attempt to compile the p4 files down to C
78 | set (XDP_TEST_SUITES "${CMAKE_CURRENT_SOURCE_DIR}/tests/xdp*.p4")
79 | p4c_add_tests("xdp" ${XDP_DRIVER} ${XDP_TEST_SUITES} "${XFAIL_TESTS_XDP}")
80 | message(STATUS "Done with configuring XDP back end")
81 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:bionic
2 |
3 | WORKDIR /home/
4 | ENV P4C_DEPS bison \
5 | build-essential \
6 | cmake \
7 | git \
8 | flex \
9 | libboost-dev \
10 | libboost-graph-dev \
11 | libboost-iostreams-dev \
12 | libfl-dev \
13 | libgc-dev \
14 | libgmp-dev \
15 | pkg-config \
16 | python3 \
17 | python3-pip \
18 | python3-setuptools
19 |
20 | ENV P4C_EBPF_DEPS libpcap-dev \
21 | libelf-dev \
22 | zlib1g-dev \
23 | llvm \
24 | clang \
25 | libprotobuf-dev \
26 | protobuf-compiler \
27 | iproute2 \
28 | tcpdump \
29 | iptables
30 |
31 | ENV P4C_PIP_PACKAGES pyroute2 \
32 | ply==3.8 \
33 | scapy==2.4.0
34 |
35 | RUN apt-get update
36 | RUN apt-get install -y --no-install-recommends $P4C_DEPS
37 | RUN apt-get install -y --no-install-recommends $P4C_EBPF_DEPS
38 | # in some cases wheel is needed to install pip packages
39 | RUN pip3 install wheel
40 | RUN pip3 install $P4C_PIP_PACKAGES
41 |
42 |
43 | # p4c download begin
44 | RUN git clone https://github.com/p4lang/p4c.git && \
45 | cd p4c && \
46 | git submodule update --init --recursive && \
47 | git submodule update --recursive && \
48 | mkdir extensions
49 | # p4c download end
50 |
51 |
52 | # copy xdp into the extension folder
53 | COPY . /home/p4c/extensions/p4c-xdp
54 | RUN ln -s /home/p4c /home/p4c/extensions/p4c-xdp
55 |
56 |
57 | # build p4c and p4c-xdp
58 | RUN cd /home/p4c/ && \
59 | python3 backends/ebpf/build_libbpf && \
60 | mkdir -p build && \
61 | cd build && \
62 | cmake .. && \
63 | make -j `getconf _NPROCESSORS_ONLN` && \
64 | make install && \
65 | cd ..
66 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # p4c-xdp
2 |
3 | This project has been archived. For a more complete ebpf XDP compiler
4 | please see the open-source p4c [repository](https://github.com/p4lang/p4c), in particular the p4c-ebpf
5 | compiler.
6 |
7 |
8 | [](https://github.com/vmware/p4c-xdp/actions/workflows/test.yml)
9 | [](https://github.com/vmware/p4c-xdp/blob/master/LICENSE)
10 | [](https://github.com/vmware/p4c-xdp/blob/master/lib/COPYING)
11 |
12 | This work presents a P4 compiler backend targeting XDP, the eXpress Data Path.
13 | P4 is a domain-specific language describing how packets are processed by the
14 | data plane of a programmable network elements, including network interface
15 | cards, appliances, and virtual switches. With P4, programmers focus on
16 | defining the protocol parsing, matching, and action executions, instead
17 | of the platform-specific language or implementation details.
18 |
19 | XDP is designed for users who want programmability as well as performance.
20 | XDP allows users to write a C-like packet processing program and loads into
21 | the device driver's receiving queue. When the device observes an incoming
22 | packet, before hanging the packet to the Linux stack, the user-defined XDP
23 | program is triggered to execute against the packet payload, making the
24 | decision as early as possible.
25 |
26 | We bring together the benefits of the two: P4 and XDP. To get started,
27 | first you need to setup the P4-16 compiler, then this project
28 | is an extension to the P4-16. To execute the XDP, you need Linux kernel
29 | version >= 4.10.0-rc7+ due to some BPF verifier limitations
30 |
31 |
32 |
33 |
34 |
35 | ## Presentations
36 | - IOVisor Summit 2017
37 | [slides](https://github.com/vmware/p4c-xdp/blob/master/doc/p4xdp-iovisor17.pdf),
38 | [demo1](https://youtu.be/On7hEJ6bPVU), [demo2](https://youtu.be/vlp1MzWVOc8), [demo3](https://youtu.be/TibGxCXPNVc)
39 | - Linux Plumbers' Conference 2018
40 | [slides](https://github.com/vmware/p4c-xdp/blob/master/doc/p4c-xdp-lpc18-presentation.pdf),
41 | [paper](https://github.com/vmware/p4c-xdp/blob/master/doc/lpc18.pdf)
42 |
43 | ## Installation
44 | ### Docker/Vagrant
45 | Please see Dockerfile. There is also a public docker image available as u9012063/p4xdp
46 | ```bash
47 | $ docker pull u9012063/p4xdp
48 | ```
49 | will pull the latest image. However, the XDP BPF code has dependency on your kernel version.
50 | Currently for some complicated cases we require kernel >= 4.10.0-rc7. So a vagrant box is
51 | also provided with kernel 4.10.0-rc8.
52 | ```bash
53 | $ vagrant init u9012063/p4xdp
54 | $ vagrant up
55 | $ vagrant ssh
56 | ubuntu@ubuntu-xenial:~$ sudo su
57 | root@ubuntu-xenial:/home/ubuntu# docker images
58 | REPOSITORY TAG IMAGE ID CREATED SIZE
59 | u9012063/p4xdp latest 3c77fbbd84e5 41 hours ago 2.469 GB
60 | root@ubuntu-xenial:/home/ubuntu# docker run -it -u root --privileged
61 | ```
62 | Will boot this VM, pull the docker image, and you can try p4c-xdp.
63 |
64 | ### P4-16 Compiler
65 | First you need to follow the installation guide of [P4-16](https://github.com/p4lang/p4c/)
66 | When you have P4-16 compiler, then add this project as an extension.
67 | Assuming you have P4-16 at your dir ~/p4c/, to setup P4C-XDP:
68 | ```bash
69 | cd ~/p4c/
70 | mkdir extensions
71 | cd extensions
72 | git clone https://github.com/vmware/p4c-xdp.git
73 | ln -s ~/p4c p4c-xdp/p4c
74 | ```
75 | Now that you have cloned p4c-xdp at ~/p4c/extensions/p4c-xdp, the next step is to
76 | recompile p4c:
77 | ```bash
78 | cd ~/p4c/
79 | mkdir -p build
80 | cd build/
81 | cmake ..
82 | make
83 | ```
84 | This generates a p4c-xdp binary in ~/p4c/build. And install the xdp test target
85 | in `backends/ebpf/targets`.
86 | Next create a soft link to the binary:
87 | ```bash
88 | cd ~/p4c/extensions/p4c-xdp
89 | ln -s ~/p4c/build/p4c-xdp p4c-xdp
90 | ```
91 | And a soft link to the test runtime:
92 | ```bash
93 | cd ~/p4c/extensions/p4c-xdp
94 | ln -s ~/p4c/backends/ebpf/run-ebpf-test.py run-ebpf-test.py
95 |
96 | ```
97 | Now you can run the p4c-xdp tests:
98 | ```
99 | cd ~/p4c/build/
100 | make check-xdp
101 | ```
102 | This will check your llvm and clang version,
103 | compile all .p4 files, generate .c files, and load them into the kernel
104 | to be checked by the BPF verifier.
105 |
106 | ## XDP: eXpress Data Path
107 | XDP is a packet processing mechanism implemented within the device driver with eBPF.
108 | Currently to compile a P4 to C program, use
109 | ```bash
110 | # ./p4c-xdp --target xdp -o
111 | ./p4c-xdp --target xdp -o /tmp/xdp1.c xdp1.p4
112 | ```
113 | then you need to compile the xdp1.c to eBPF bytecode, xdp1.o, then load it
114 | into your driver. To compile a single .c file
115 | ```bash
116 | clang -Wno-unused-value -Wno-pointer-sign \
117 | -Wno-compare-distinct-pointer-types \
118 | -Wno-gnu-variable-sized-type-not-at-end \
119 | -Wno-tautological-compare \
120 | -O2 -emit-llvm -g -c /tmp/xdp1.c -o -| llc -march=bpf -filetype=obj -o /tmp/xdp1.o
121 | ```
122 | Then load it into the driver with XDP support
123 | ```bash
124 | ip link set dev $DEV xdp obj xdp1.o verb
125 | ```
126 | to unload the XDP object
127 | ```bash
128 | ip link set dev $DEV xdp off
129 | ```
130 | ## Sample Code
131 | Please see the [tests folder](https://github.com/vmware/p4c-xdp/tree/master/tests)
132 | Simply run 'make' will start the build
133 |
134 | ## Related BPF/XDP work
135 | * Dive into BPF: a list of reading material, Quentin Monnet [link](https://qmonnet.github.io/whirl-offload/2016/09/01/dive-into-bpf/)
136 | * BPF: Next Generation of Programmable Datapath by Thomas Graf, OVS Conf 2016 [video](https://www.youtube.com/watch?v=QJfmmoH2nSQ&t=1046s)
137 | * Fast Programmable Networks & Encapsulated Protocols, David S. Miller, netdev 1.2 [video](https://www.youtube.com/watch?v=NlMQ0i09HMU)
138 |
139 | ## License
140 | The p4c-xdp/lib/\* contains BPF loader licensed under the [General Public License, Version 2.0](lib/COPYING). The rest of p4c-xdp components are licensed under the [Apache License, Version 2.0](LICENSE).
141 |
142 | ## TODO
143 | * Remove the private kernel patch requirement when latest kernel with BPF fixed is ready
144 | * Apply the workaround of BPF\_MAX\_STACK
145 | * Control plane example using perf\_event\_output
146 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | Vagrant.configure(2) do |config|
5 | # The most common configuration options are documented and commented below.
6 | # For a complete reference, please see the online documentation at
7 | # https://docs.vagrantup.com.
8 |
9 | config.vm.box = "ubuntu/xenial64"
10 |
11 | # Disable automatic box update checking. If you disable this, then
12 | # boxes will only be checked for updates when the user runs
13 | # `vagrant box outdated`. This is not recommended.
14 | config.vm.box_check_update = false
15 | config.vm.provision "shell", inline: <<-SHELL
16 | sudo apt-get update
17 | sudo apt-get install -y build-essential dpkg
18 |
19 | # Kernel v4.11-rc1
20 | # This has our latest changes to BPF verifier
21 | # However the MAX_BPF_STACK issue hasn't been resolved.
22 | wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.11-rc1/linux-image-4.11.0-041100rc1-generic_4.11.0-041100rc1.201703051731_amd64.deb
23 | dpkg -i linux-image-4.11.0-041100rc1-generic_4.11.0-041100rc1.201703051731_amd64.deb
24 | wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.11-rc1/linux-headers-4.11.0-041100rc1-generic_4.11.0-041100rc1.201703051731_amd64.deb
25 | dpkg -i linux-headers-4.11.0-041100rc1-generic_4.11.0-041100rc1.201703051731_amd64.deb
26 | wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.11-rc1/linux-headers-4.11.0-041100rc1_4.11.0-041100rc1.201703051731_all.deb
27 | dpkg -i linux-headers-4.11.0-041100rc1_4.11.0-041100rc1.201703051731_all.deb
28 |
29 | # Fetch the p4xdp docker image
30 | apt-get install -y docker.io
31 | docker pull u9012063/p4xdp
32 | SHELL
33 | # reboot to the newer kernel
34 | config.vm.provision :reload
35 | end
36 |
37 |
--------------------------------------------------------------------------------
/compile-bpf.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | KERNEL=/root/net-next/
3 |
4 | echo "ebpf filename:" $1
5 |
6 | clang -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/5.4.0/include/ \
7 | -I../ -I$KERNEL/arch/x86/include -I$KERNEL/arch/x86/include/generated/uapi \
8 | -I$KERNEL/arch/x86/include/generated -I$KERNEL/include \
9 | -I$KERNEL/arch/x86/include/uapi \
10 | -I$KERNEL/include/uapi -I$KERNEL/include/generated/uapi \
11 | -include $KERNEL/include/linux/kconfig.h \
12 | -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
13 | -Wno-compare-distinct-pointer-types -emit-llvm -O2 -c $1 -o -| \
14 | llc -march=bpf -filetype=obj -o tmp.o
15 |
16 | echo "output to tmp.o"
17 |
18 | exit 0
19 | ./p4test --p4-14 ../backends/p4c-ovs-ebpf/ovs-parse.p4
20 | ./p4test --pp x.p4 --p4-14 ../backends/p4c-ovs-ebpf/ovs-parse.p4
21 |
22 |
--------------------------------------------------------------------------------
/doc/images/p4xdp-workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/images/p4xdp-workflow.png
--------------------------------------------------------------------------------
/doc/lpc18.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/lpc18.pdf
--------------------------------------------------------------------------------
/doc/lpc18/.gitignore:
--------------------------------------------------------------------------------
1 | *.aux
2 | *.log
3 | top.pdf
4 | top.out
5 | *.bbl
6 | *.blg
7 | *.synctex.gz
8 |
--------------------------------------------------------------------------------
/doc/lpc18/Makefile:
--------------------------------------------------------------------------------
1 | TEXFILES = background.tex compilation.tex conclusions.tex introduction.tex results.tex testing.tex top.tex
2 | FIGURES =
3 | GRAPHS =
4 |
5 | top.pdf: $(FIGURES) $(TEXFILES) $(GRAPHS)
6 | texi2pdf top.tex -o p4cxdp-lpc18.pdf
7 | xdg-open p4cxdp-lpc18.pdf
8 |
9 | clean: clean-graphs clean-figures
10 | rm -f top.bbl top.blg top.log top.aux
11 | rm -f p4cxdp-lpc18.pdf
12 |
13 | clean-graphs:
14 | rm -f $(GRAPHS)
15 |
16 | clean-figures:
17 | rm -f $(FIGURES)
18 |
19 | %.pdf: %.eps
20 | epstopdf $< > $@
21 |
--------------------------------------------------------------------------------
/doc/lpc18/architecture.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/lpc18/architecture.pdf
--------------------------------------------------------------------------------
/doc/lpc18/compilation.tex:
--------------------------------------------------------------------------------
1 | \section{Compiling P4 to eBPF}\label{sec:compilation}
2 |
3 | In this section we describe two open-source compilers that translate
4 | P4 programs in stylized C programs, that can in turn be compiled into
5 | eBPF programs using the LLVM eBPF back-end.
6 |
7 | \subsection{Packet filters with eBPF}\label{sec:ebpf}
8 |
9 | The eBPF back-end is part of the P4 reference compiler
10 | implementation~\cite{p4-ebpf-backend}. This back-end targets a
11 | relatively simple packet filter architecture.
12 | Figure~\ref{fig:ebpf-model} shows the architectural model of an eBPF
13 | packet filter expressed in P4. This architecture comprises a parser
14 | and a control block; the control block must produce a Boolean value
15 | which indicates whether the packet is accepted or not.
16 |
17 | \begin{figure}[h]
18 | \begin{lstlisting}
19 | #include
20 |
21 | extern CounterArray {
22 | CounterArray(bit<32> max_index, bool sparse);
23 | void increment(in bit<32> index);
24 | }
25 |
26 | extern array_table {
27 | array_table(bit<32> size);
28 | }
29 |
30 | extern hash_table {
31 | hash_table(bit<32> size);
32 | }
33 |
34 | parser parse(packet_in packet, out H headers);
35 | control filter(in H headers, out bool accept);
36 |
37 | package ebpfFilter(parse prs,
38 | filter filt);
39 | \end{lstlisting}
40 | \caption{Packet filter P4 architectural model for an eBPF
41 | target.}\label{fig:ebpf-model}
42 | \end{figure}
43 |
44 | Figure~\ref{fig:count} shows a P4 program written for this
45 | architecture that counts the number of IPv4 packets that are
46 | encountered.
47 |
48 | \begin{figure}
49 | \begin{lstlisting}
50 | #include
51 | #include
52 |
53 | typedef bit<48> EthernetAddress;
54 | typedef bit<32> IPv4Address;
55 |
56 | header Ethernet {
57 | EthernetAddress dstAddr;
58 | EthernetAddress srcAddr;
59 | bit<16> etherType;
60 | }
61 |
62 | // IPv4 header without options
63 | header IPv4 {
64 | bit<4> version;
65 | bit<4> ihl;
66 | bit<8> diffserv;
67 | bit<16> totalLen;
68 | bit<16> identification;
69 | bit<3> flags;
70 | bit<13> fragOffset;
71 | bit<8> ttl;
72 | bit<8> protocol;
73 | bit<16> hdrChecksum;
74 | IPv4Address srcAddr;
75 | IPv4Address dstAddr;
76 | }
77 |
78 | struct Headers {
79 | Ethernet eth;
80 | IPv4 ipv4;
81 | }
82 |
83 | parser prs(packet_in p, out Headers headers) {
84 | state start {
85 | p.extract(headers.eth);
86 | transition select(headers.eth.etherType) {
87 | 0x800 : ip;
88 | default : reject;
89 | }
90 | }
91 |
92 | state ip {
93 | p.extract(headers.ipv4);
94 | transition accept;
95 | }
96 | }
97 |
98 | control pipe(in Headers headers, out bool pass){
99 | CounterArray(32w10, true) ctr;
100 |
101 | apply {
102 | if (headers.ipv4.isValid()) {
103 | ctr.increment(headers.ipv4.dstAddr);
104 | pass = true;
105 | } else
106 | pass = false;
107 | }
108 | }
109 |
110 | // Instantiate main package
111 | ebpfFilter(prs(), pipe()) main;
112 | \end{lstlisting}
113 | \caption{A P4 program that counts the number of IPv4 packets
114 | encountered.}\label{fig:count}
115 | \end{figure}
116 |
117 | Compilation to C is fairly straightforward; the generated C program is
118 | always memory-safe, using bounds-checks for all packet accesses. For
119 | the entire P4 program a single C function is generated which returns a
120 | Boolean value. Table~\ref{table:translation} shows how each P4
121 | construct is converted to a C construct. Currently programs with
122 | parser loops are rejected, but a parser loop unrolling pass (under
123 | development) will allow such programs to be compiled.
124 |
125 | \begin{table}[h]
126 | \footnotesize
127 | \begin{tabular}{|l|p{4.8cm}|} \hline
128 | \textbf{P4 construct} & \textbf{C Translation} \\ \hline \hline
129 | \texttt{header} & \texttt{struct} with an additional \texttt{valid} bit \\ \hline
130 | \texttt{struct} & \texttt{struct} \\ \hline
131 | parser state & block statement \\ \hline
132 | state transition & \texttt{goto} statement \\ \hline
133 | \texttt{extract} call & load/shift/mask data from packet \\ \hline
134 | table & 2 eBPF maps --- one for actions, one for the default action \\ \hline
135 | table key type & \texttt{struct} type \\ \hline
136 | \texttt{action} & tagged \texttt{union} with action parameters \\ \hline
137 | \texttt{action} parameters & \texttt{struct} \\ \hline
138 | \texttt{action} body & block statement \\ \hline
139 | table \texttt{apply} & lookup in eBFP map + \texttt{switch} statement with all actions \\ \hline
140 | counters & eBPF map \\ \hline
141 | \end{tabular}
142 | \caption{Compiling P4 constructs to C.}\label{table:translation}
143 | \end{table}
144 |
145 | \subsection{Packet forwarding with XDP}\label{sec:xdp}
146 |
147 |
148 | A second P4 to C compiler, P4C-XDP, is available as an open-source
149 | project hosted at~\cite{p4-xdp-backend}. P4C-XDP is licensed under the GNU
150 | GPL and Apache License.
151 | This compiler extends the eBPF compiler from Section~\ref{sec:ebpf}. It can
152 | target either a packet filter, or a packet switch. The following listing shows
153 | the XDP architectural model targeted by this compiler. You can see that a
154 | P4 XDP program can (1) return to the kernel one of the four outcomes
155 | described in Section~\ref{sec:xdp-background}, and (2) it can also
156 | modify the packet itself, by inserting, modifying or deleting headers.
157 |
158 | \begin{figure}
159 | \begin{lstlisting}
160 | #include
161 | enum xdp_action {
162 | XDP_ABORTED,
163 | XDP_DROP,
164 | XDP_PASS,
165 | XDP_TX
166 | }
167 | struct xdp_input { bit<32> input_port }
168 |
169 | struct xdp_output {
170 | xdp_action output_action;
171 | bit<32> output_port;
172 | }
173 |
174 | parser xdp_parse(packet_in packet,
175 | out H headers);
176 | control xdp_switch(inout H hdrs,
177 | in xdp_input i,
178 | out xdp_output o);
179 | control xdp_deparse(in H headers,
180 | packet_out packet);
181 |
182 | package xdp(xdp_parse p,
183 | xdp_switch s,
184 | xdp_deparse d);
185 | \end{lstlisting}
186 | \caption{XDP packet switching architectural
187 | model.}\label{fig:xdp-model}
188 | \end{figure}
189 |
--------------------------------------------------------------------------------
/doc/lpc18/conclusions.tex:
--------------------------------------------------------------------------------
1 | \section{Lessons learned}\label{sec:conclusions}
2 |
3 | In general, our development experience is mirrored by the lessons described
4 | in~\cite{minao-hspr18} and ~\cite{bertin-netdev17}.
5 |
6 | \paragraph{No multi-/broadcast support}
7 | While XDP is able to redirect single frames it does not have the ability to
8 | clone and redirect multiple packets similar to \texttt{bpf\_clone\_redirect}.
9 | This makes development of more sophisticated P4 forwarding programs problematic.
10 |
11 | \paragraph{The stack size is too small}
12 | More complex generated XDP programs are rejected by the verifier despite their
13 | safeness.
14 | This is a particular challenge when attempting to implement network function
15 | chaining or advanced pipelined packet processing in a single XDP program.
16 |
17 | \paragraph{Generic XDP and TCP}
18 | Our testing framework uses virtual Linux interfaces and generic
19 | XDP~\cite{genericxdp} to verify XDP programs.
20 | Unfortunately, we are unable to test TCP streams as the protocol is not
21 | supported by this driver~\cite{xdptcp}.
22 | Any program loaded by generic XDP operates after the creation of
23 | the \texttt{skb} and requires the original packet data. Since TCP clones every
24 | packet and passes the unmodifiable \texttt{skb} clone, generic XDP is
25 | bypassed and never receives the datagram.
26 |
27 | \paragraph{Using the libbpf userspace library}
28 | Compilation of eBPF programs in user-space requires substantial
29 | effort. Many function calls and variables available in sample programs are not
30 | available as general C library. Any user trying to interact with the
31 | generated C code has to provide their own sources. Currently, P4C-XDP maintains
32 | copies of utilities from kernel code or various online sources. This is not a
33 | sustainable approach. We plan to integrate \texttt{libbpf} with our repository
34 | to control and manage the eBPF programs and maps.
35 |
36 | \paragraph{Pinned eBPF maps in network namespaces}
37 | When using eBPF programs in namespaces, maps that were pinned via \texttt{tc}
38 | do not persist across \texttt{ip netns exec} calls. As consequence, any
39 | program has to be run in a single continuous shell command. Example:
40 | {\scriptsize
41 | \begin{verbatim}
42 | bash -c "tc filter add ...; ls /sys/fs/bpf/tc/globals"
43 | \end{verbatim}
44 | }
45 | Once \texttt{ip netns exec} has finished, the reference to the eBPF
46 | map and all its associated state disappear. The eBPF program, however, remains
47 | attached to the virtual interface, leading to inconsistent packet processing
48 | behavior.
49 |
50 |
--------------------------------------------------------------------------------
/doc/lpc18/introduction.tex:
--------------------------------------------------------------------------------
1 | \section{Introduction}\label{sec:introduction}
2 |
3 | The introduction of Software Defined Networking (SDN)~\cite{rfc7426}
4 | has decoupled the network control-plane from the data-plane. The Open
5 | Flow Protocol~\cite{mckeown-ccr08} is a typical incarnation of SDN.
6 | Even though SDN makes the control-plane programmable, it still assumes
7 | that the {data-plane} is fixed. The inability to program data-planes
8 | is a significant impediment to innovation: for example, the deployment
9 | of the VxLAN protocol~\cite{rfc7348} took 4 years between the initial
10 | proposal and its commercial availability in high-speed devices.
11 |
12 | To address this state of affairs, \cite{bosshart-ccr14} introduced the
13 | P4 language: Programming Protocol-independent Packet Processors, which
14 | is designed to make the behavior of \emph{data-planes} expressible as
15 | software. P4 has gained rapid adoption. The p4.org
16 | consortium~\cite{p4org} was created to steward the language evolution;
17 | p4.org currently includes more than 100 organizations in the areas of
18 | networking, cloud systems, network chip design, and academic
19 | institutions. The P4 specification is open and
20 | public~\cite{p416-spec17}. Reference implementations for compilers,
21 | simulation and debugging tools are available with a permissive license
22 | at the GitHub P4 repository~\cite{p4lang}. While initially P4 was
23 | designed for programming network switches, its scope has been
24 | broadened to cover a large variety of packet-processing systems (e.g.,
25 | network cards, FPGAs, etc.).
26 |
--------------------------------------------------------------------------------
/doc/lpc18/kernel_test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/lpc18/kernel_test.png
--------------------------------------------------------------------------------
/doc/lpc18/p4cxdp-lpc18.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/lpc18/p4cxdp-lpc18.pdf
--------------------------------------------------------------------------------
/doc/lpc18/results.tex:
--------------------------------------------------------------------------------
1 | \section{Experimental results}\label{sec:results}
2 | \subsection{Testbed}
3 | All of our performance results use a hardware testbed that consists of
4 | two Intel Xeon E5 2440 v2 1.9GHz servers, each with 1 CPU socket and
5 | 8 physical cores with hyperthreading enabled.
6 | Each target server has an Intel 10GbE X540-AT2 dual
7 | port NIC, with the two ports of the Intel NIC on one server connected
8 | to the two ports on the identical NIC on the other server.
9 | We installed p4c-xdp on one server, the {\em target server}, and
10 | attached the XDP program to the port that receives the packets
11 | The other server, the {\em source server}, generates packets
12 | at the maximum 10~Gbps packet rate of 14.88~Mpps using the DPDK-based
13 | TRex~\cite{trex} traffic generator. The source server sends minimum
14 | length 64-byte packets in a {\em single} UDP flow to one port of the
15 | target server, and receives the forwarded packets on the same port.
16 | At the target server, we use only one core to process all packets.
17 | Every packet received goes through the pipeline specified in P4.
18 |
19 | We use the sample p4 programs in the tests directory and the following
20 | metrics to understand the performance impact of the P4-generated XDP
21 | program:
22 | \begin{itemize}
23 | \item Packet Processing Rate (Mpps): Once the XDP program finishes
24 | processing the packet, it returns one of the actions mentioned in
25 | section~\ref{sec:background}. When we want to count the number of
26 | packets that can be dropped per second, we modify each p4 program to
27 | always return XDP\_DROP.
28 | \item CPU Utilization: Every packet processed by the XDP program is run
29 | under the per-core software IRQ daemon, named
30 | \texttt{ksoftirqd/\textit{core}}. All packets are processed by only
31 | one core with one kthread, the ksoftirqd, and we measure the CPU
32 | utilization of the ksoftirqd on the core.
33 | \item Number of BPF instructions verified: For each program, we list
34 | the complexity as the number of BPF instructions the eBPF
35 | verifier scans.
36 | \end{itemize}
37 |
38 | The target server is running Linux kernel 4.19-rc5 and for all our
39 | tests, the BPF JIT (Just-In-Time) compiler is enabled and JIT hardening
40 | is disabled. All programs are compiled with clang 3.8 with llvm 5.0.
41 | For each test program, we use the following
42 | command from iproute2 to load it into kernel:
43 | \begin{lstlisting}[frame=none]
44 | ip link set dev eth0 xdp obj xdp1.o verb
45 | \end{lstlisting}
46 |
47 | The Intel 10GbE X540 NIC is running the \texttt{ixgbe} driver with 16 RX queues
48 | set-up. Since the source server is sending single UDP flow, packets
49 | always arrive at a single queue ID. As a result, we collect the number
50 | of packets being dropped at this queue.
51 |
52 | \subsection{Results}
53 |
54 | To compute the baseline performance we wrote two small XDP programs by
55 | hand: \texttt{SimpleDrop}, drops all packets by returning
56 | \texttt{XDP\_DROP} immediately. \texttt{SimpleTX} forwards the packet
57 | to the receiving port returning \texttt{XDP\_TX}. Each of these
58 | programs consists of only two BPF instructions.
59 |
60 | \begin{lstlisting}[frame=none]
61 | /* SimpleDrop */
62 | 0: (b7) r0 = 1 // XDP_DROP
63 | 1: (95) exit
64 |
65 | /* SimpleTX */
66 | 0: (b7) r0 = 3 // XDP_TX
67 | 1: (95) exit
68 | \end{lstlisting}
69 |
70 | After, we attached the following P4 programs to the receiving device:
71 | \begin{itemize}
72 | \item xdp1.p4: Parse Ethernet/IPv4 header, deparse it, and drop.
73 | \item xdp3.p4: Parse Ethernet/IPv4 header, lookup a MAC address
74 | in a map, deparse it, and drop.
75 | \item xdp6.p4: Parse Ethernet/IPv4 header, lookup and get a new TTL value
76 | from eBPF map, set to IPv4 header, deparse it, and drop.
77 | \item xdp7.p4: Parse Ethernet/IPv4/UDP header, write a pre-defined source port
78 | and source IP, recalculate checksum, deparse, and drop.
79 | \item xdp11.p4: Parse Ethernet/IPv4 header, swap src/dst MAC address,
80 | deparse it, and send back to the same port (XDP\_TX).
81 | \item xdp15.p4: Parse Ethernet header, insert a customized 8-byte header,
82 | deparse it, and send back to the same port (XDP\_TX).
83 | \end{itemize}
84 |
85 | \begin{table}
86 | \centering
87 | \small
88 | \begin{tabular}{llll}
89 | \underline{P4 program} & \underline{CPU Util.} & \underline{Mpps} & \underline{Insns./Stack}\\
90 | SimpleDrop & 75\% & 14.4 & 2/0 \\
91 | SimpleTX & 100\% & 7.2 & 2/0 \\
92 | xdp1.p4 & 100\% & 8.1 & 277/256 \\
93 | xdp3.p4 & 100\% & 7.1 & 326/256 \\
94 | xdp6.p4 & 100\% & 2.5 & 335/272 \\
95 | xdp7.p4 & 100\% & 5.7 & 5821/336 \\
96 | xdp11.p4 & 100\% & 4.7 & 335/216 \\
97 | xdp15.p4 & 100\% & 5.5 & 96/56\\
98 | \end{tabular}
99 | \caption{\footnotesize Performance of XDP program generated by
100 | p4c-xdp compiler using single core.}
101 | \label{tab:perf}
102 | \end{table}
103 |
104 | As shown in Table~\ref{tab:perf}, xdp1.p4 allows us to measure the
105 | overhead introduced by parsing and deparsing: a drop from 14.4~Mpps to
106 | 8.1~Mpps. xdp3.p4 reduces the rate by another million PPS due to the
107 | eBPF map lookup (this operation always returns NULL, no value from the
108 | map is accessed). xdp6.p4 has significant overhead because it
109 | accesses a map, finds a new TTL value, and writes to the IPv4 header.
110 | Interestingly, although xdp7.p4 does extra parsing to the UDP header
111 | and checksum recalculation, it has only a moderate overhead because of
112 | the lack of map accesses.
113 |
114 | Finally, xdp11.p4 and xdp15.p4 show the transmit (XDP\_TX)
115 | performance. Compared with xdp11, xdp15.p4 invokes the
116 | \texttt{bpf\_adjust\_head} helper function to reset the pointer for extra
117 | bytes. It does not incur much overhead because there
118 | is already a reserved space in front of every XDP packet frame.
119 |
120 | \subsection{Performance Analysis}
121 |
122 | To further understand the performance overhead of programs generated
123 | by p4c-xdp, we started broke down the CPU utilization. We used the Linux
124 | perf tool on the process ID of the ksoftirqd that shows 100\%:
125 | \begin{lstlisting}[frame=none]
126 | perf record -p sleep 10
127 | \end{lstlisting}
128 |
129 |
130 | \noindent The following output shows the profile of xdp1.p4:
131 | {\scriptsize
132 | \begin{verbatim}
133 | 83.19% [kernel.kallsyms] [k] ___bpf_prog_run
134 | 8.14% [ixgbe] [k] ixgbe_clean_rx_irq
135 | 4.82% [kernel.kallsyms] [k] nmi
136 | 1.48% [kernel.kallsyms] [k] bpf_xdp_adjust_head
137 | 1.07% [kernel.kallsyms] [k] __rcu_read_unlock
138 | 0.40% [ixgbe] [k] ixgbe_alloc_rx_buffers
139 | \end{verbatim}
140 | }
141 |
142 | This confirms that most of the CPU cycles are spent on executing the
143 | XDP program, \texttt{\_\_\_bpf\_prog\_run}, which caused us to investigate the
144 | eBPF C code of xdp1.p4.
145 |
146 | \begin{table}
147 | \centering
148 | \small
149 | \begin{tabular}{llll}
150 | \underline{P4 program} & \underline{CPU Util.} & \underline{Mpps} & \underline{Insns./Stack}\\
151 | xdp1.p4 & 77\% & 14.8 & 26/0 \\
152 | xdp3.p4 & 100\% & 13 & 100/16 \\
153 | xdp6.p4 & 100\% & 12 & 98/40 \\
154 | \end{tabular}
155 | \caption{\footnotesize Performance of XDP program without deparser.}
156 | \label{tab:perf2}
157 | \end{table}
158 |
159 | After commenting out the deparser C code, performance increases
160 | significantly (see Table~\ref{tab:perf2}). In the generated
161 | code, the p4c-xdp compiler always writes back the entire packet
162 | content, even when the P4 program does not modify any fields. In
163 | addition, the parser/deparser incur byte-order translation, e.g.,
164 | htonl, ntohl. This could be avoided by always using network
165 | byte-order in P4 and XDP. We plan to implement optimizations to
166 | reduce this overhead.
167 |
--------------------------------------------------------------------------------
/doc/lpc18/stf.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/lpc18/stf.pdf
--------------------------------------------------------------------------------
/doc/lpc18/stf.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/lpc18/stf.vsdx
--------------------------------------------------------------------------------
/doc/lpc18/testing.tex:
--------------------------------------------------------------------------------
1 | \section{Testing eBPF programs}\label{sec:testing}
2 |
3 | To test the P4 to C compilers we have adapted and extended the
4 | existing P4 testing infrastructure. The infrastructure can perform
5 | both functional correctness testing at the user level, and complete
6 | end-to-end testing running programs in the kernel.
7 |
8 | \subsection{User-Space Testing}
9 |
10 | User-space testing validates the correctness of the code generated by
11 | compiler and can be performed even on systems that lack eBPF support
12 | in the kernel. The user space testing framework does not depend on
13 | the LLVM~\cite{llvm} or any particular kernel version. It also does
14 | not require usage of \texttt{iproute2}~\cite{iproute} tooling such as
15 | \texttt{tc} or \texttt{ip}. It is also easier to debug failing tests
16 | in user-space, by using tools such as GDB~\cite{gdb},
17 | Valgrind~\cite{valgrind}, or Wireshark~\cite{wireshark}.
18 |
19 | \begin{table}[h]
20 | \footnotesize
21 | \begin{center}
22 | \begin{tabular}{|p{2.8cm}|p{4.3cm}|} \hline
23 | \textbf{Command} & \textbf{Description} \\ \hline \hline
24 | \textbf{packet} port data & Insert a frame of bytes
25 | \textit{data} into port \textit{port}. \\ \hline
26 | \textbf{expect} port data & Expect a frame of bytes
27 | \textit{data} on port \textit{port}. \\ \hline
28 | \textbf{add} tbl priority match action & Insert a
29 | match-action entry with key \textit{match} and action
30 | \textit{action} into table \textit{tbl}. \\ \hline
31 | \textbf{setdefault} tbl action & Set the default action for table
32 | \textit{tbl}. \\
33 | \hline
34 | \textbf{check\_counter} tbl key==n & Check if the value on
35 | the entry \textit{key} in counter table \textit{tbl} matches
36 | \textit{n}. \\
37 | \hline
38 | \textbf{wait} & Pause for a second. \\ \hline
39 | \end{tabular}
40 | \caption{The STF command palette.}\label{table:stf}
41 | \end{center}
42 | \end{table}
43 |
44 | \subsection{The Simple Test Framework}
45 | \begin{figure}
46 | \centering
47 | \includegraphics[width=\linewidth]{stf}
48 | \caption{Annotated example of a Simple Testing Framework (STF)
49 | program for testing the P4 compiler.}
50 | \label{fig:stf}
51 | \end{figure}
52 |
53 | The P4 compiler includes a simple language (STF = Simple Testing
54 | Framework) to describe input/output packets and to populate P4 tables.
55 | Initially STF was used with software simulators to validate P4
56 | programs, but we have adapted it for testing the eBPF and XDP
57 | back-ends. The STF framework is written in Python.
58 | Figure~\ref{fig:stf} shows a small program written in the STF
59 | language. Table \ref{table:stf} describes the list of currently
60 | supported STF operations in the eBPF testing backend.
61 |
62 | The STF \texttt{packet} statement describes an input port and the
63 | contents of a inbound packet. The \texttt{expect} statement describes
64 | an output port and the contents of an outbound packet.
65 |
66 | Tables can be populated using the \texttt{add} statement, which
67 | indicates a P4 table and an action to insert in the table, including
68 | values for the action parameters. Currently we assume that all
69 | \texttt{add} statements are executed prior to all the packet
70 | manipulation statements.
71 |
72 | Our testing framework converts \texttt{packet} statements into PCAP
73 | (Packet CAPture) files, one for each input port tested. \texttt{add}
74 | statements are converted into C programs that populate eBPF maps.
75 |
76 | Although STF supports testing counters as well, our eBPF testing
77 | framework does not yet support this feature.
78 |
79 | \begin{figure*}
80 | \centering
81 | \includegraphics[width=\linewidth]{testing_workflow}
82 | \caption{Testing workflow for a P4-eBPF program. Environment and
83 | target are provided by the user.}
84 | \label{fig:p4_testflow}
85 | \end{figure*}
86 |
87 | \subsection{The Test Runtime}
88 |
89 | Executing a P4 eBPF test is done in five stages (Figure
90 | \ref{fig:p4_testflow}):
91 |
92 | \begin{enumerate}
93 | \item\textbf{compile-p4:} Compile the P4 file to C program.
94 | \item \textbf{parse-stf:} Convert the STF file to a C program and into
95 | input PCAP files.
96 | \item \textbf{compile-data-plane:} Compile and load the C programs
97 | into an executable.
98 | \item \textbf{run:} Wire up the executable to read from the input PCAP
99 | files; run the executable -- first populate tables then execute the
100 | program over the input packets. Capture the produced output packets
101 | into output files.
102 | \item \textbf{check-results:} Compare the output packets with the
103 | expected results.
104 | \end{enumerate}
105 |
106 | \noindent These five stages look slightly differently when testing in
107 | user-space and in kernel-space.
108 |
109 | In user space we use a hash-table library to emulate eBPF maps.
110 |
111 | When testing in kernel-space we compile the eBPF/XDP programs to eBPF
112 | object files using LLVM. Before the eBPF/XDP program is loaded, the
113 | framework creates a bridge running in a network namespace.
114 | Namespace-based isolation allows us to run multiple tests in parallel.
115 | Virtual interfaces are attached to the bridge. The testing runtime
116 | injects packets into the associated ports using raw sockets. The
117 | output results are recorded by attaching Tcpdump~\cite{tcpdump} to
118 | each output virtual interface.
119 |
--------------------------------------------------------------------------------
/doc/lpc18/testing_workflow.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/lpc18/testing_workflow.pdf
--------------------------------------------------------------------------------
/doc/lpc18/testing_workflow.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/lpc18/testing_workflow.vsdx
--------------------------------------------------------------------------------
/doc/lpc18/top.tex:
--------------------------------------------------------------------------------
1 | \documentclass[9pt,twocolumn,times]{article}
2 |
3 | \usepackage{color}
4 | \usepackage{caption}
5 | \usepackage{float}
6 | \usepackage{courier}
7 | \usepackage{xspace}
8 | \usepackage{url}
9 | \usepackage{listings}
10 | \usepackage{graphicx}
11 | \usepackage{mdframed}
12 | \usepackage[letterpaper, margin=1in]{geometry}
13 | \usepackage{enumitem}
14 | \usepackage[compact]{titlesec}
15 |
16 | \setitemize{noitemsep,topsep=0pt,parsep=0pt,partopsep=0pt,leftmargin=.5cm}
17 | \setlist[itemize]{noitemsep,topsep=0pt,parsep=0pt,partopsep=0pt,leftmargin=.5cm}
18 | \setlist[enumerate]{noitemsep,topsep=0pt,parsep=0pt,partopsep=0pt,leftmargin=.5cm}
19 | \setlist[description]{noitemsep,topsep=0pt,parsep=0pt,partopsep=0pt,leftmargin=.5cm}
20 |
21 | \lstset{
22 | language=C,
23 | basicstyle=\ttfamily\footnotesize,
24 | frame=lrbt,
25 | morekeywords={action,apply,bit,bool,%
26 | const,control,default,else,%
27 | enum,error,extern,exit,%
28 | false,header,header_union,if,%
29 | in,inout,int,match_kind,%
30 | package,parser,out,return,%
31 | select,state,struct,switch,%
32 | table,transition,true,tuple%
33 | typedef,varbit,verify,void,%
34 | %
35 | abstract,interface,class,virtual% used for IR
36 | }
37 | }
38 |
39 | \newcommand{\code}[1]{\texttt{#1}}
40 | \newcommand{\keyword}[1]{{\bf \texttt{#1}}}
41 | \newcommand{\vonemodel}{\code{v1model}\xspace}
42 | \newcommand{\mycomment}[1]{}
43 |
44 | \title{Linux Network Programming with P4}
45 | \author{William Tu\\
46 | VMware Inc.\\
47 | \texttt{tuc@vmware.com}
48 | \and
49 | Fabian Ruffy\\
50 | University of British Columbia\\
51 | \texttt{fruffy@cs.ubc.ca}
52 | \and
53 | Mihai Budiu\\
54 | VMware Research\\
55 | \texttt{mbudiu@vmware.com}
56 | }
57 | \date{}
58 |
59 | \begin{document}
60 | \maketitle
61 |
62 | \begin{abstract}
63 | P4 is a domain-specific language for implementing network data-planes.
64 | The P4 abstraction allows programmers to write network protocols in a
65 | generalized fashion, without needing to know the configuration specifics
66 | of the targeted data-plane.
67 |
68 | The extended Berkely Packet Filter (eBPF) is a safe virtual machine for
69 | executing sand-boxed programs in the Linux kernel. eBPF, and its extension
70 | the eXpress Data Path (XDP), effectively serve as programmable data-planes of
71 | the kernel.
72 |
73 | P4C-XDP is a project combining the performance of XDP with the generality and
74 | usability of P4. In this document, we describe how P4 can be
75 | translated into eBPF/XDP. We review the fundamental limitations of both
76 | technologies, analyze the performance of several generated XDP programs, and
77 | discuss problems we have faced while working on this new technology.
78 |
79 | \end{abstract}
80 |
81 |
82 | \input{introduction}
83 | \input{background}
84 | \input{compilation}
85 | \input{testing}
86 | \input{results}
87 | \input{conclusions}
88 |
89 | \bibliography{top}
90 | \bibliographystyle{acm}
91 |
92 | \end{document}
93 |
--------------------------------------------------------------------------------
/doc/lpc18/user_test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/lpc18/user_test.png
--------------------------------------------------------------------------------
/doc/p4c-xdp-lpc18-presentation.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/p4c-xdp-lpc18-presentation.pdf
--------------------------------------------------------------------------------
/doc/p4xdp-iovisor17.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vmware-archive/p4c-xdp/00dabaefc384668f4939ad9a1621ecf099ff88fe/doc/p4xdp-iovisor17.pdf
--------------------------------------------------------------------------------
/doc/perf.txt:
--------------------------------------------------------------------------------
1 | 03/24/2017
2 | Performance test using ixgbe XDP dirver
3 | sender is using DPDK pktgen, receiving side is running XDP
4 |
5 | === sender at server prmh-138 ===
6 | root@prmh-nsx-perf-server138:~/dpdk/pktgen-dpdk-new# ./pktgendpdk.sh pcap/test1.pcap
7 |
8 | === XDP receiver ===
9 | root@prmh-nsx-perf-server139:# echo 1 > /proc/sys/net/core/bpf_jit_enable
10 | root@prmh-nsx-perf-server139:# ip link set dev enp5s0f1 xdp obj xdp11.o
11 |
12 | === xdp2_kern.c ===
13 | # at receiving side
14 | $ sar -n DEV 1
15 | 03:33:16 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
16 | 3:33:17 PM enp5s0f1 1139681.00 1139681.00 231286.55 231286.55 0.00 0.00 0.00 18.95
17 |
18 | $ perf top
19 | 53.42% [kernel] [k] __bpf_prog_run
20 | 2.57% [kernel] [k] menu_select
21 | 2.22% [kernel] [k] cpuidle_enter_state
22 | 2.19% [kernel] [k] irq_entries_start
23 | 1.66% [kernel] [k] __tick_nohz_idle_enter
24 | 1.35% [kernel] [k] copy_page
25 | 1.25% [kernel] [k] napi_complete_done
26 | 1.17% [kernel] [k] swiotlb_sync_single_for_device
27 | 0.98% [kernel] [k] percpu_array_map_lookup_elem
28 |
29 | === xdp11.o ===
30 | 03:33:16 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
31 | 03:47:36 PM enp5s0f1 1139756.00 1139735.00 231301.22 231295.65 0.00 0.00 0.00 18.95
32 |
33 | 71.04% [kernel] [k] __bpf_prog_run
34 | 2.56% [kernel] [k] page_frag_free
35 | 0.87% [kernel] [k] cpuidle_enter_state
36 | 0.73% [kernel] [k] irq_entries_start
37 | 0.64% [kernel] [k] memcpy_erms
38 | 0.63% [kernel] [k] menu_select
39 |
40 | 88.43% [kernel] [k] __bpf_prog_run
41 | 0.98% [kernel] [k] memcpy_erms
42 | 0.57% [kernel] [k] irq_entries_start
43 | 0.49% [kernel] [k] swiotlb_map_page
44 | 0.46% [kernel] [k] __tick_nohz_idle_enter
45 | 0.43% [kernel] [k] array_map_update_elem
46 | 0.32% [kernel] [k] cpuidle_enter_state
47 |
48 | === xdp9 (force to do XDP_TX) ===
49 | 03:33:16 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
50 | 03:52:59 PM enp5s0f1 1139754.00 1139722.00 231299.64 222388.89 0.00 0.00 0.00 18.95
51 | 87.06% [kernel] [k] __bpf_prog_run
52 | 0.59% [kernel] [k] memcpy_erms
53 | 0.55% [kernel] [k] htab_map_lookup_elem
54 | 0.55% [kernel] [k] menu_select
55 | 0.53% [kernel] [k] __htab_map_lookup_elem
56 | 0.48% [kernel] [k] array_map_lookup_elem
57 | 0.47% [kernel] [k] __tick_nohz_idle_enter
58 |
59 |
--------------------------------------------------------------------------------
/lib/Makefile:
--------------------------------------------------------------------------------
1 | CC = gcc
2 |
3 | all: libbpf.o bpf_load.o
4 |
5 | libbpf.o: libbpf.c libbpf.h
6 | $(CC) -g -c libbpf.c
7 |
8 | bpf_load.o: bpf_load.c bpf_load.h
9 | $(CC) -g -c bpf_load.c
10 |
11 | clean:
12 | @rm -f *.o
13 |
--------------------------------------------------------------------------------
/lib/bpf_helpers.h:
--------------------------------------------------------------------------------
1 | #ifndef __BPF_HELPERS_H
2 | #define __BPF_HELPERS_H
3 |
4 | /* helper macro to place programs, maps, license in
5 | * different sections in elf_bpf file. Section names
6 | * are interpreted by elf_bpf loader
7 | */
8 | #define SEC(NAME) __attribute__((section(NAME), used))
9 |
10 | /* helper functions called from eBPF programs written in C */
11 | static void *(*bpf_map_lookup_elem)(void *map, void *key) =
12 | (void *) BPF_FUNC_map_lookup_elem;
13 | static int (*bpf_map_update_elem)(void *map, void *key, void *value,
14 | unsigned long long flags) =
15 | (void *) BPF_FUNC_map_update_elem;
16 | static int (*bpf_map_delete_elem)(void *map, void *key) =
17 | (void *) BPF_FUNC_map_delete_elem;
18 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) =
19 | (void *) BPF_FUNC_probe_read;
20 | static unsigned long long (*bpf_ktime_get_ns)(void) =
21 | (void *) BPF_FUNC_ktime_get_ns;
22 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
23 | (void *) BPF_FUNC_trace_printk;
24 | static void (*bpf_tail_call)(void *ctx, void *map, int index) =
25 | (void *) BPF_FUNC_tail_call;
26 | static unsigned long long (*bpf_get_smp_processor_id)(void) =
27 | (void *) BPF_FUNC_get_smp_processor_id;
28 | static unsigned long long (*bpf_get_current_pid_tgid)(void) =
29 | (void *) BPF_FUNC_get_current_pid_tgid;
30 | static unsigned long long (*bpf_get_current_uid_gid)(void) =
31 | (void *) BPF_FUNC_get_current_uid_gid;
32 | static int (*bpf_get_current_comm)(void *buf, int buf_size) =
33 | (void *) BPF_FUNC_get_current_comm;
34 | static int (*bpf_perf_event_read)(void *map, int index) =
35 | (void *) BPF_FUNC_perf_event_read;
36 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) =
37 | (void *) BPF_FUNC_clone_redirect;
38 | static int (*bpf_redirect)(int ifindex, int flags) =
39 | (void *) BPF_FUNC_redirect;
40 | static int (*bpf_perf_event_output)(void *ctx, void *map,
41 | unsigned long long flags, void *data,
42 | int size) =
43 | (void *) BPF_FUNC_perf_event_output;
44 | static int (*bpf_get_stackid)(void *ctx, void *map, int flags) =
45 | (void *) BPF_FUNC_get_stackid;
46 | static int (*bpf_probe_write_user)(void *dst, void *src, int size) =
47 | (void *) BPF_FUNC_probe_write_user;
48 | static int (*bpf_current_task_under_cgroup)(void *map, int index) =
49 | (void *) BPF_FUNC_current_task_under_cgroup;
50 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) =
51 | (void *) BPF_FUNC_skb_get_tunnel_key;
52 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) =
53 | (void *) BPF_FUNC_skb_set_tunnel_key;
54 | static int (*bpf_skb_get_tunnel_opt)(void *ctx, void *md, int size) =
55 | (void *) BPF_FUNC_skb_get_tunnel_opt;
56 | static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) =
57 | (void *) BPF_FUNC_skb_set_tunnel_opt;
58 | static unsigned long long (*bpf_get_prandom_u32)(void) =
59 | (void *) BPF_FUNC_get_prandom_u32;
60 | static int (*bpf_xdp_adjust_head)(void *ctx, int offset) =
61 | (void *) BPF_FUNC_xdp_adjust_head;
62 |
63 |
64 | /* llvm builtin functions that eBPF C program may use to
65 | * emit BPF_LD_ABS and BPF_LD_IND instructions
66 | */
67 | struct sk_buff;
68 | unsigned long long load_byte(void *skb,
69 | unsigned long long off) asm("llvm.bpf.load.byte");
70 | unsigned long long load_half(void *skb,
71 | unsigned long long off) asm("llvm.bpf.load.half");
72 | unsigned long long load_word(void *skb,
73 | unsigned long long off) asm("llvm.bpf.load.word");
74 |
75 | /* a helper structure used by eBPF C program
76 | * to describe map attributes to elf_bpf loader
77 | */
78 | struct bpf_map_def {
79 | unsigned int type;
80 | unsigned int key_size;
81 | unsigned int value_size;
82 | unsigned int max_entries;
83 | unsigned int map_flags;
84 | /* we need this for tc, not for bpf syscall */
85 | unsigned int id;
86 | unsigned int pinning;
87 | };
88 |
89 | static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) =
90 | (void *) BPF_FUNC_skb_load_bytes;
91 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) =
92 | (void *) BPF_FUNC_skb_store_bytes;
93 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) =
94 | (void *) BPF_FUNC_l3_csum_replace;
95 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) =
96 | (void *) BPF_FUNC_l4_csum_replace;
97 | static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) =
98 | (void *) BPF_FUNC_skb_under_cgroup;
99 | static int (*bpf_skb_change_head)(void *, int len, int flags) =
100 | (void *) BPF_FUNC_skb_change_head;
101 |
102 | #if defined(__x86_64__)
103 |
104 | #define PT_REGS_PARM1(x) ((x)->di)
105 | #define PT_REGS_PARM2(x) ((x)->si)
106 | #define PT_REGS_PARM3(x) ((x)->dx)
107 | #define PT_REGS_PARM4(x) ((x)->cx)
108 | #define PT_REGS_PARM5(x) ((x)->r8)
109 | #define PT_REGS_RET(x) ((x)->sp)
110 | #define PT_REGS_FP(x) ((x)->bp)
111 | #define PT_REGS_RC(x) ((x)->ax)
112 | #define PT_REGS_SP(x) ((x)->sp)
113 | #define PT_REGS_IP(x) ((x)->ip)
114 |
115 | #elif defined(__s390x__)
116 |
117 | #define PT_REGS_PARM1(x) ((x)->gprs[2])
118 | #define PT_REGS_PARM2(x) ((x)->gprs[3])
119 | #define PT_REGS_PARM3(x) ((x)->gprs[4])
120 | #define PT_REGS_PARM4(x) ((x)->gprs[5])
121 | #define PT_REGS_PARM5(x) ((x)->gprs[6])
122 | #define PT_REGS_RET(x) ((x)->gprs[14])
123 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */
124 | #define PT_REGS_RC(x) ((x)->gprs[2])
125 | #define PT_REGS_SP(x) ((x)->gprs[15])
126 | #define PT_REGS_IP(x) ((x)->psw.addr)
127 |
128 | #elif defined(__aarch64__)
129 |
130 | #define PT_REGS_PARM1(x) ((x)->regs[0])
131 | #define PT_REGS_PARM2(x) ((x)->regs[1])
132 | #define PT_REGS_PARM3(x) ((x)->regs[2])
133 | #define PT_REGS_PARM4(x) ((x)->regs[3])
134 | #define PT_REGS_PARM5(x) ((x)->regs[4])
135 | #define PT_REGS_RET(x) ((x)->regs[30])
136 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */
137 | #define PT_REGS_RC(x) ((x)->regs[0])
138 | #define PT_REGS_SP(x) ((x)->sp)
139 | #define PT_REGS_IP(x) ((x)->pc)
140 |
141 | #elif defined(__powerpc__)
142 |
143 | #define PT_REGS_PARM1(x) ((x)->gpr[3])
144 | #define PT_REGS_PARM2(x) ((x)->gpr[4])
145 | #define PT_REGS_PARM3(x) ((x)->gpr[5])
146 | #define PT_REGS_PARM4(x) ((x)->gpr[6])
147 | #define PT_REGS_PARM5(x) ((x)->gpr[7])
148 | #define PT_REGS_RC(x) ((x)->gpr[3])
149 | #define PT_REGS_SP(x) ((x)->sp)
150 | #define PT_REGS_IP(x) ((x)->nip)
151 |
152 | #endif
153 |
154 | #ifdef __powerpc__
155 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; })
156 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP
157 | #else
158 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ \
159 | bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })
160 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ \
161 | bpf_probe_read(&(ip), sizeof(ip), \
162 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
163 | #endif
164 |
165 | #endif
166 |
--------------------------------------------------------------------------------
/lib/bpf_load.h:
--------------------------------------------------------------------------------
1 | #ifndef __BPF_LOAD_H
2 | #define __BPF_LOAD_H
3 |
4 | #define MAX_MAPS 32
5 | #define MAX_PROGS 32
6 |
7 | extern int map_fd[MAX_MAPS];
8 | extern int prog_fd[MAX_PROGS];
9 | extern int event_fd[MAX_PROGS];
10 | extern int prog_cnt;
11 |
12 | /* parses elf file compiled by llvm .c->.o
13 | * . parses 'maps' section and creates maps via BPF syscall
14 | * . parses 'license' section and passes it to syscall
15 | * . parses elf relocations for BPF maps and adjusts BPF_LD_IMM64 insns by
16 | * storing map_fd into insn->imm and marking such insns as BPF_PSEUDO_MAP_FD
17 | * . loads eBPF programs via BPF syscall
18 | *
19 | * One ELF file can contain multiple BPF programs which will be loaded
20 | * and their FDs stored stored in prog_fd array
21 | *
22 | * returns zero on success
23 | */
24 | int load_bpf_file(char *path);
25 |
26 | void read_trace_pipe(void);
27 | struct ksym {
28 | long addr;
29 | char *name;
30 | };
31 |
32 | int load_kallsyms(void);
33 | struct ksym *ksym_search(long key);
34 | int set_link_xdp_fd(int ifindex, int fd);
35 | #endif
36 |
--------------------------------------------------------------------------------
/lib/libbpf.c:
--------------------------------------------------------------------------------
1 | /* eBPF mini library */
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include "libbpf.h"
15 |
16 | static __u64 ptr_to_u64(void *ptr)
17 | {
18 | return (__u64) (unsigned long) ptr;
19 | }
20 |
21 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
22 | int max_entries)
23 | {
24 | union bpf_attr attr = {
25 | .map_type = map_type,
26 | .key_size = key_size,
27 | .value_size = value_size,
28 | .max_entries = max_entries,
29 | };
30 |
31 | return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
32 | }
33 |
34 | int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags)
35 | {
36 | union bpf_attr attr = {
37 | .map_fd = fd,
38 | .key = ptr_to_u64(key),
39 | .value = ptr_to_u64(value),
40 | .flags = flags,
41 | };
42 |
43 | return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
44 | }
45 |
46 | int bpf_lookup_elem(int fd, void *key, void *value)
47 | {
48 | union bpf_attr attr = {
49 | .map_fd = fd,
50 | .key = ptr_to_u64(key),
51 | .value = ptr_to_u64(value),
52 | };
53 |
54 | return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
55 | }
56 |
57 | int bpf_delete_elem(int fd, void *key)
58 | {
59 | union bpf_attr attr = {
60 | .map_fd = fd,
61 | .key = ptr_to_u64(key),
62 | };
63 |
64 | return syscall(__NR_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
65 | }
66 |
67 | int bpf_get_next_key(int fd, void *key, void *next_key)
68 | {
69 | union bpf_attr attr = {
70 | .map_fd = fd,
71 | .key = ptr_to_u64(key),
72 | .next_key = ptr_to_u64(next_key),
73 | };
74 |
75 | return syscall(__NR_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
76 | }
77 |
78 | #define ROUND_UP(x, n) (((x) + (n) - 1u) & ~((n) - 1u))
79 |
80 | char bpf_log_buf[LOG_BUF_SIZE];
81 |
82 | int bpf_prog_load(enum bpf_prog_type prog_type,
83 | const struct bpf_insn *insns, int prog_len,
84 | const char *license, int kern_version)
85 | {
86 | union bpf_attr attr = {
87 | .prog_type = prog_type,
88 | .insns = ptr_to_u64((void *) insns),
89 | .insn_cnt = prog_len / sizeof(struct bpf_insn),
90 | .license = ptr_to_u64((void *) license),
91 | .log_buf = ptr_to_u64(bpf_log_buf),
92 | .log_size = LOG_BUF_SIZE,
93 | .log_level = 1,
94 | };
95 |
96 | /* assign one field outside of struct init to make sure any
97 | * padding is zero initialized
98 | */
99 | attr.kern_version = kern_version;
100 |
101 | bpf_log_buf[0] = 0;
102 |
103 | return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
104 | }
105 |
106 | int bpf_obj_pin(int fd, const char *pathname)
107 | {
108 | union bpf_attr attr = {
109 | .pathname = ptr_to_u64((void *)pathname),
110 | .bpf_fd = fd,
111 | };
112 |
113 | return syscall(__NR_bpf, BPF_OBJ_PIN, &attr, sizeof(attr));
114 | }
115 |
116 | int bpf_obj_get(const char *pathname)
117 | {
118 | union bpf_attr attr = {
119 | .pathname = ptr_to_u64((void *)pathname),
120 | };
121 |
122 | return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
123 | }
124 |
125 | int open_raw_sock(const char *name)
126 | {
127 | struct sockaddr_ll sll;
128 | int sock;
129 |
130 | sock = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, htons(ETH_P_ALL));
131 | if (sock < 0) {
132 | printf("cannot create raw socket\n");
133 | return -1;
134 | }
135 |
136 | memset(&sll, 0, sizeof(sll));
137 | sll.sll_family = AF_PACKET;
138 | sll.sll_ifindex = if_nametoindex(name);
139 | sll.sll_protocol = htons(ETH_P_ALL);
140 | if (bind(sock, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
141 | printf("bind to %s\n", name);
142 | close(sock);
143 | return -1;
144 | }
145 |
146 | return sock;
147 | }
148 |
149 | int perf_event_open(struct perf_event_attr *attr, int pid, int cpu,
150 | int group_fd, unsigned long flags)
151 | {
152 | return syscall(__NR_perf_event_open, attr, pid, cpu,
153 | group_fd, flags);
154 | }
155 |
--------------------------------------------------------------------------------
/lib/libbpf.h:
--------------------------------------------------------------------------------
1 | /* eBPF mini library */
2 | #ifndef __LIBBPF_H
3 | #define __LIBBPF_H
4 |
5 | struct bpf_insn;
6 |
7 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
8 | int max_entries);
9 | int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
10 | int bpf_lookup_elem(int fd, void *key, void *value);
11 | int bpf_delete_elem(int fd, void *key);
12 | int bpf_get_next_key(int fd, void *key, void *next_key);
13 |
14 | int bpf_prog_load(enum bpf_prog_type prog_type,
15 | const struct bpf_insn *insns, int insn_len,
16 | const char *license, int kern_version);
17 |
18 | int bpf_obj_pin(int fd, const char *pathname);
19 | int bpf_obj_get(const char *pathname);
20 |
21 | #define LOG_BUF_SIZE 262144
22 | extern char bpf_log_buf[LOG_BUF_SIZE];
23 |
24 | /* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
25 |
26 | #define BPF_ALU64_REG(OP, DST, SRC) \
27 | ((struct bpf_insn) { \
28 | .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \
29 | .dst_reg = DST, \
30 | .src_reg = SRC, \
31 | .off = 0, \
32 | .imm = 0 })
33 |
34 | #define BPF_ALU32_REG(OP, DST, SRC) \
35 | ((struct bpf_insn) { \
36 | .code = BPF_ALU | BPF_OP(OP) | BPF_X, \
37 | .dst_reg = DST, \
38 | .src_reg = SRC, \
39 | .off = 0, \
40 | .imm = 0 })
41 |
42 | /* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
43 |
44 | #define BPF_ALU64_IMM(OP, DST, IMM) \
45 | ((struct bpf_insn) { \
46 | .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
47 | .dst_reg = DST, \
48 | .src_reg = 0, \
49 | .off = 0, \
50 | .imm = IMM })
51 |
52 | #define BPF_ALU32_IMM(OP, DST, IMM) \
53 | ((struct bpf_insn) { \
54 | .code = BPF_ALU | BPF_OP(OP) | BPF_K, \
55 | .dst_reg = DST, \
56 | .src_reg = 0, \
57 | .off = 0, \
58 | .imm = IMM })
59 |
60 | /* Short form of mov, dst_reg = src_reg */
61 |
62 | #define BPF_MOV64_REG(DST, SRC) \
63 | ((struct bpf_insn) { \
64 | .code = BPF_ALU64 | BPF_MOV | BPF_X, \
65 | .dst_reg = DST, \
66 | .src_reg = SRC, \
67 | .off = 0, \
68 | .imm = 0 })
69 |
70 | #define BPF_MOV32_REG(DST, SRC) \
71 | ((struct bpf_insn) { \
72 | .code = BPF_ALU | BPF_MOV | BPF_X, \
73 | .dst_reg = DST, \
74 | .src_reg = SRC, \
75 | .off = 0, \
76 | .imm = 0 })
77 |
78 | /* Short form of mov, dst_reg = imm32 */
79 |
80 | #define BPF_MOV64_IMM(DST, IMM) \
81 | ((struct bpf_insn) { \
82 | .code = BPF_ALU64 | BPF_MOV | BPF_K, \
83 | .dst_reg = DST, \
84 | .src_reg = 0, \
85 | .off = 0, \
86 | .imm = IMM })
87 |
88 | /* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */
89 | #define BPF_LD_IMM64(DST, IMM) \
90 | BPF_LD_IMM64_RAW(DST, 0, IMM)
91 |
92 | #define BPF_LD_IMM64_RAW(DST, SRC, IMM) \
93 | ((struct bpf_insn) { \
94 | .code = BPF_LD | BPF_DW | BPF_IMM, \
95 | .dst_reg = DST, \
96 | .src_reg = SRC, \
97 | .off = 0, \
98 | .imm = (__u32) (IMM) }), \
99 | ((struct bpf_insn) { \
100 | .code = 0, /* zero is reserved opcode */ \
101 | .dst_reg = 0, \
102 | .src_reg = 0, \
103 | .off = 0, \
104 | .imm = ((__u64) (IMM)) >> 32 })
105 |
106 | #ifndef BPF_PSEUDO_MAP_FD
107 | # define BPF_PSEUDO_MAP_FD 1
108 | #endif
109 |
110 | /* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */
111 | #define BPF_LD_MAP_FD(DST, MAP_FD) \
112 | BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD)
113 |
114 |
115 | /* Direct packet access, R0 = *(uint *) (skb->data + imm32) */
116 |
117 | #define BPF_LD_ABS(SIZE, IMM) \
118 | ((struct bpf_insn) { \
119 | .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \
120 | .dst_reg = 0, \
121 | .src_reg = 0, \
122 | .off = 0, \
123 | .imm = IMM })
124 |
125 | /* Memory load, dst_reg = *(uint *) (src_reg + off16) */
126 |
127 | #define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \
128 | ((struct bpf_insn) { \
129 | .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \
130 | .dst_reg = DST, \
131 | .src_reg = SRC, \
132 | .off = OFF, \
133 | .imm = 0 })
134 |
135 | /* Memory store, *(uint *) (dst_reg + off16) = src_reg */
136 |
137 | #define BPF_STX_MEM(SIZE, DST, SRC, OFF) \
138 | ((struct bpf_insn) { \
139 | .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \
140 | .dst_reg = DST, \
141 | .src_reg = SRC, \
142 | .off = OFF, \
143 | .imm = 0 })
144 |
145 | /* Memory store, *(uint *) (dst_reg + off16) = imm32 */
146 |
147 | #define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
148 | ((struct bpf_insn) { \
149 | .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \
150 | .dst_reg = DST, \
151 | .src_reg = 0, \
152 | .off = OFF, \
153 | .imm = IMM })
154 |
155 | /* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */
156 |
157 | #define BPF_JMP_REG(OP, DST, SRC, OFF) \
158 | ((struct bpf_insn) { \
159 | .code = BPF_JMP | BPF_OP(OP) | BPF_X, \
160 | .dst_reg = DST, \
161 | .src_reg = SRC, \
162 | .off = OFF, \
163 | .imm = 0 })
164 |
165 | /* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */
166 |
167 | #define BPF_JMP_IMM(OP, DST, IMM, OFF) \
168 | ((struct bpf_insn) { \
169 | .code = BPF_JMP | BPF_OP(OP) | BPF_K, \
170 | .dst_reg = DST, \
171 | .src_reg = 0, \
172 | .off = OFF, \
173 | .imm = IMM })
174 |
175 | /* Raw code statement block */
176 |
177 | #define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \
178 | ((struct bpf_insn) { \
179 | .code = CODE, \
180 | .dst_reg = DST, \
181 | .src_reg = SRC, \
182 | .off = OFF, \
183 | .imm = IMM })
184 |
185 | /* Program exit */
186 |
187 | #define BPF_EXIT_INSN() \
188 | ((struct bpf_insn) { \
189 | .code = BPF_JMP | BPF_EXIT, \
190 | .dst_reg = 0, \
191 | .src_reg = 0, \
192 | .off = 0, \
193 | .imm = 0 })
194 |
195 | /* create RAW socket and bind to interface 'name' */
196 | int open_raw_sock(const char *name);
197 |
198 | struct perf_event_attr;
199 | int perf_event_open(struct perf_event_attr *attr, int pid, int cpu,
200 | int group_fd, unsigned long flags);
201 | #endif
202 |
--------------------------------------------------------------------------------
/ovs-parse-14.p4:
--------------------------------------------------------------------------------
1 | /* OVS P4 header file
2 | * - Copy header from include/headers.p4, parser.p4 at github.com/p4lang/switch.git
3 | * - Copy struct definition from OVS
4 | */
5 |
6 | #define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
7 | #define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
8 | #define ETH_P_ARP 0x0806
9 | #define ETH_P_IPV4 0x0800
10 | #define ETH_P_IPV6 0x86DD
11 |
12 | #define IPPROTO_ICMP 1
13 | #define IPPROTO_IGMP 2
14 | #define IPPROTO_TCP 6
15 | #define IPPROTO_UDP 17
16 | #define IPPROTO_GRE 47
17 | #define IPPROTO_SCTP 132
18 |
19 | header_type ethernet_t {
20 | fields {
21 | dstAddr : 48;
22 | srcAddr : 48;
23 | etherType : 16;
24 | }
25 | }
26 |
27 | header_type vlan_tag_t {
28 | fields {
29 | pcp : 3;
30 | cfi : 1;
31 | vid : 12;
32 | etherType : 16;
33 | }
34 | }
35 |
36 | header_type mpls_t {
37 | fields {
38 | label : 20;
39 | exp : 3;
40 | bos : 1;
41 | ttl : 8;
42 | }
43 | }
44 |
45 | header_type arp_rarp_t {
46 | fields {
47 | hwType : 16;
48 | protoType : 16;
49 | hwAddrLen : 8;
50 | protoAddrLen : 8;
51 | opcode : 16;
52 | }
53 | }
54 |
55 | header_type arp_rarp_ipv4_t {
56 | fields {
57 | srcHwAddr : 48;
58 | srcProtoAddr : 32;
59 | dstHwAddr : 48;
60 | dstProtoAddr : 32;
61 | }
62 | }
63 |
64 | header_type ipv4_t {
65 | fields {
66 | version : 4;
67 | ihl : 4;
68 | diffserv : 8;
69 | totalLen : 16;
70 | identification : 16;
71 | flags : 3;
72 | fragOffset : 13;
73 | ttl : 8;
74 | protocol : 8;
75 | hdrChecksum : 16;
76 | srcAddr : 32;
77 | dstAddr: 32;
78 | }
79 | }
80 |
81 | header_type ipv6_t {
82 | fields {
83 | version : 4;
84 | trafficClass : 8;
85 | flowLabel : 20;
86 | payloadLen : 16;
87 | nextHdr : 8;
88 | hopLimit : 8;
89 | srcAddr : 128;
90 | dstAddr : 128;
91 | }
92 | }
93 |
94 | header_type icmp_t {
95 | fields {
96 | typeCode : 16;
97 | hdrChecksum : 16;
98 | }
99 | }
100 |
101 | header_type tcp_t {
102 | fields {
103 | srcPort : 16;
104 | dstPort : 16;
105 | seqNo : 32;
106 | ackNo : 32;
107 | dataOffset : 4;
108 | res : 4;
109 | flags : 8;
110 | window : 16;
111 | checksum : 16;
112 | urgentPtr : 16;
113 | }
114 | }
115 |
116 | header_type udp_t {
117 | fields {
118 | srcPort : 16;
119 | dstPort : 16;
120 | length_ : 16;
121 | checksum : 16;
122 | }
123 | }
124 |
125 | header_type sctp_t {
126 | fields {
127 | srcPort : 16;
128 | dstPort : 16;
129 | verifTag : 32;
130 | checksum : 32;
131 | }
132 | }
133 |
134 | header_type gre_t {
135 | fields {
136 | C : 1;
137 | R : 1;
138 | K : 1;
139 | S : 1;
140 | s : 1;
141 | recurse : 3;
142 | flags : 5;
143 | ver : 3;
144 | proto : 16;
145 | }
146 | }
147 | /* ----------------- metadata ---------------- */
148 | header_type pkt_metadata_t {
149 | fields {
150 | recirc_id : 32; /* Recirculation id carried with the
151 | recirculating packets. 0 for packets
152 | received from the wire. */
153 | dp_hash : 32; /* hash value computed by the recirculation
154 | action. */
155 | skb_priority : 32; /* Packet priority for QoS. */
156 | pkt_mark : 32; /* Packet mark. */
157 | ct_state : 16; /* Connection state. */
158 | ct_zone : 16; /* Connection zone. */
159 | ct_mark : 32; /* Connection mark. */
160 | ct_label : 128; /* Connection label. */
161 | in_port : 32; /* Input port. */
162 | }
163 | }
164 |
165 | header_type flow_tnl_t {
166 | fields {
167 | /* struct flow_tnl:
168 | * Tunnel information used in flow key and metadata.
169 | */
170 | ip_dst : 32;
171 | ipv6_dst : 64;
172 | ip_src: 32;
173 | ipv6_src : 64;
174 | tun_id : 64;
175 | flags : 16;
176 | ip_tos : 8;
177 | ip_ttl : 8;
178 | tp_src : 16;
179 | tp_dst : 16;
180 | gbp_id : 16;
181 | gbp_flags : 8;
182 | pad1: 40; /* Pad to 64 bits. */
183 | /* struct tun_metadata metadata; */
184 | }
185 | }
186 |
187 | header ethernet_t ethernet;
188 | header ipv4_t ipv4;
189 | header ipv6_t ipv6;
190 | header arp_rarp_t arp;
191 | header tcp_t tcp;
192 | header udp_t udp;
193 | header icmp_t icmp;
194 | header vlan_tag_t vlan;
195 | metadata pkt_metadata_t md;
196 | metadata flow_tnl_t tnl_md;
197 |
198 | /* ------------------ A tree, no loop is allowed -------------------------------- */
199 |
200 | parser start {
201 | return parse_ethernet;
202 | }
203 |
204 | parser parse_ethernet{
205 | extract(ethernet);
206 | return select(latest.etherType) {
207 | ETH_P_8021Q: parse_vlan;
208 | ETH_P_8021AD: parse_vlan;
209 | ETH_P_ARP: parse_arp;
210 | ETH_P_IPV4: parse_ipv4;
211 | ETH_P_IPV6: parse_ipv6;
212 | default: ingress;
213 | }
214 | }
215 |
216 | parser parse_vlan {
217 | extract(vlan);
218 | return select(latest.etherType) {
219 | ETH_P_ARP: parse_arp;
220 | ETH_P_IPV4: parse_ipv4;
221 | ETH_P_IPV6: parse_ipv6;
222 | default: ingress;
223 | }
224 | }
225 |
226 | parser parse_arp {
227 | extract(arp);
228 | return ingress;
229 | }
230 |
231 | parser parse_ipv4 {
232 | extract(ipv4);
233 | return select(latest.protocol) {
234 | IPPROTO_TCP: parse_tcp;
235 | IPPROTO_UDP: parse_udp;
236 | IPPROTO_ICMP: parse_icmp;
237 | default: ingress;
238 | }
239 | }
240 |
241 | parser parse_ipv6 {
242 | extract(ipv6);
243 | return select(latest.nextHdr) {
244 | IPPROTO_TCP: parse_tcp;
245 | IPPROTO_UDP: parse_udp;
246 | IPPROTO_ICMP: parse_icmp;
247 | default: ingress;
248 | }
249 | }
250 |
251 | parser parse_tcp {
252 | extract(tcp);
253 | return ingress;
254 | }
255 |
256 | parser parse_udp {
257 | extract(udp);
258 | return ingress;
259 | }
260 |
261 | parser parse_icmp {
262 | extract(icmp);
263 | return ingress;
264 | }
265 |
266 | /* ------------------------------------------------------------------------- */
267 |
268 | action nop() {}
269 |
270 | table ovs_tbl {
271 | reads {
272 | /* we are not using it. */
273 | ipv4.dstAddr: exact;
274 | md.in_port: exact;
275 | tnl_md.tun_id: exact;
276 | }
277 | actions {
278 | nop;
279 | }
280 | }
281 |
282 | control ingress
283 | {
284 | apply(ovs_tbl);
285 | }
286 |
287 |
--------------------------------------------------------------------------------
/ovs.p4:
--------------------------------------------------------------------------------
1 | /*
2 | OVS.p4 using tc-ebpf P4 architecture
3 | Requirements:
4 | - This should be an example which uses tc-ebpf P4 model to implement
5 | all the protocols supported by OVS.
6 |
7 | Protocol supports:
8 | - L2: VLAN,...
9 | - L3: ...
10 | Tunneling:
11 | - Support Linux's bpf tunnel protocol (ipip, vxlan, gre, geneve, etc)
12 | */
13 |
14 | // TODO: define a new model ovs_ebpf_model.p4
15 | #include
16 |
17 | #define OUTPUT_OFS (1<<0)
18 | #define PUSHVLAN_OFS (1<<1)
19 | #define POPVLAN_OFS (1<<2)
20 | #define SETMASKED_OFS (1<<3)
21 | #define SETTUNEL_OFS (1<<4)
22 | #define TRUNC_OFS (1<<5)
23 |
24 | extern void bpf_skb_clone_redirect(in bit<16> port);
25 | extern void bpf_skb_vlan_push(in bit<16> proto, in bit<16> tci);
26 | extern void bpf_skb_vlan_pop();
27 |
28 | struct pkt_metadata_t {
29 | bit<32> recirc_id;
30 | bit<32> dp_hash;
31 | bit<32> skb_priority;
32 | bit<32> pkt_mark;
33 | bit<16> ct_state;
34 | bit<16> ct_zone;
35 | bit<32> ct_mark;
36 | bit<128> ct_label;
37 | bit<32> in_port;
38 | }
39 |
40 | struct flow_tnl_t {
41 | bit<32> ip_dst;
42 | bit<64> ipv6_dst;
43 | bit<32> ip_src;
44 | bit<64> ipv6_src;
45 | bit<64> tun_id;
46 | bit<16> flags;
47 | bit<8> ip_tos;
48 | bit<8> ip_ttl;
49 | bit<16> tp_src;
50 | bit<16> tp_dst;
51 | bit<16> gbp_id;
52 | bit<8> gbp_flags;
53 | bit<40> pad1;
54 | }
55 |
56 | header arp_rarp_t {
57 | bit<16> hwType;
58 | bit<16> protoType;
59 | bit<8> hwAddrLen;
60 | bit<8> protoAddrLen;
61 | bit<16> opcode;
62 | }
63 |
64 | header ethernet_t {
65 | bit<48> dstAddr;
66 | bit<48> srcAddr;
67 | bit<16> etherType;
68 | }
69 |
70 | header icmp_t {
71 | bit<16> typeCode;
72 | bit<16> hdrChecksum;
73 | }
74 |
75 | header ipv4_t {
76 | bit<4> version;
77 | bit<4> ihl;
78 | bit<8> diffserv;
79 | bit<16> totalLen;
80 | bit<16> identification;
81 | bit<3> flags;
82 | bit<13> fragOffset;
83 | bit<8> ttl;
84 | bit<8> protocol;
85 | bit<16> hdrChecksum;
86 | bit<32> srcAddr;
87 | bit<32> dstAddr;
88 | }
89 |
90 | header ipv6_t {
91 | bit<4> version;
92 | bit<8> trafficClass;
93 | bit<20> flowLabel;
94 | bit<16> payloadLen;
95 | bit<8> nextHdr;
96 | bit<8> hopLimit;
97 | bit<128> srcAddr;
98 | bit<128> dstAddr;
99 | }
100 |
101 | header tcp_t {
102 | bit<16> srcPort;
103 | bit<16> dstPort;
104 | bit<32> seqNo;
105 | bit<32> ackNo;
106 | bit<4> dataOffset;
107 | bit<4> res;
108 | bit<8> flags;
109 | bit<16> window;
110 | bit<16> checksum;
111 | bit<16> urgentPtr;
112 | }
113 |
114 | header udp_t {
115 | bit<16> srcPort;
116 | bit<16> dstPort;
117 | bit<16> length_;
118 | bit<16> checksum;
119 | }
120 |
121 | header vlan_tag_t {
122 | bit<3> pcp;
123 | bit<1> cfi;
124 | bit<12> vid;
125 | bit<16> etherType;
126 | }
127 |
128 | struct metadata {
129 | pkt_metadata_t md;
130 | flow_tnl_t tnl;
131 | }
132 |
133 | struct ovs_packet {
134 | arp_rarp_t arp;
135 | ethernet_t ethernet;
136 | icmp_t icmp;
137 | ipv4_t ipv4;
138 | ipv6_t ipv6;
139 | tcp_t tcp;
140 | udp_t udp;
141 | vlan_tag_t vlan;
142 | }
143 |
144 | // metadata to execute on actions
145 | struct output_md_t {
146 | bit<16> port; //ifindex
147 | }
148 |
149 | struct pushvlan_md_t {
150 | bit<16> tci;
151 | bit<16> proto;
152 | }
153 |
154 | struct settunnel_md_t {
155 | bit<32> ip_dst;
156 | bit<32> ip_src;
157 | bit<64> tun_id;
158 | bit<16> flags;
159 | }
160 |
161 | // it's better if we have union
162 | struct action_md_t {
163 | output_md_t output;
164 | pushvlan_md_t pushvlan;
165 | settunnel_md_t settunnel;
166 | }
167 |
168 | /* implement OVS's key_extract() in net/openvswitch/flow.c */
169 | parser TopParser(packet_in packet, /*inout bpf_sk_buff skbU, */ out ovs_packet hdr)
170 | {
171 | state parse_arp {
172 | packet.extract(hdr.arp);
173 | transition accept;
174 | }
175 | state parse_ethernet {
176 | packet.extract(hdr.ethernet);
177 | transition select(hdr.ethernet.etherType) {
178 | 16w0x8100: parse_vlan;
179 | 16w0x88a8: parse_vlan;
180 | 16w0x806: parse_arp;
181 | 16w0x800: parse_ipv4;
182 | 16w0x86dd: parse_ipv6;
183 | default: accept;
184 | }
185 | }
186 | state parse_icmp {
187 | packet.extract(hdr.icmp);
188 | transition accept;
189 | }
190 | state parse_ipv4 {
191 | packet.extract(hdr.ipv4);
192 | transition select(hdr.ipv4.protocol) {
193 | 8w6: parse_tcp;
194 | 8w17: parse_udp;
195 | 8w1: parse_icmp;
196 | default: accept;
197 | }
198 | }
199 | state parse_ipv6 {
200 | packet.extract(hdr.ipv6);
201 | transition select(hdr.ipv6.nextHdr) {
202 | 8w6: parse_tcp;
203 | 8w17: parse_udp;
204 | 8w1: parse_icmp;
205 | default: accept;
206 | }
207 | }
208 | state parse_tcp {
209 | packet.extract(hdr.tcp);
210 | transition accept;
211 | }
212 | state parse_udp {
213 | packet.extract(hdr.udp);
214 | transition accept;
215 | }
216 | state parse_vlan {
217 | packet.extract(hdr.vlan);
218 | transition select(hdr.vlan.etherType) {
219 | 16w0x806: parse_arp;
220 | 16w0x800: parse_ipv4;
221 | 16w0x86dd: parse_ipv6;
222 | default: accept;
223 | }
224 | }
225 | state start {
226 | transition parse_ethernet;
227 | }
228 | }
229 |
230 |
231 | control Ingress(inout ovs_packet hdr,
232 | out bool pass)
233 | {
234 | // TODO: This should become an in parameter of Ingress
235 | metadata md;
236 | // TODO: this should become an out parameter of Ingress
237 | bit<16> outputPort;
238 | bit<32> toRun;
239 | action_md_t action_md;
240 |
241 | action Output()
242 | {
243 | outputPort = action_md.output.port;
244 | //bpf_skb_clone_redirect(outputPort);
245 | }
246 |
247 | action PushVlan()
248 | {
249 | bit<16> tci = action_md.pushvlan.tci;
250 | bit<16> proto = action_md.pushvlan.proto;
251 | //bpf_skb_vlan_push(proto, tci);
252 | }
253 |
254 | action PopVlan()
255 | {
256 | //bpf_skb_vlan_pop();
257 | }
258 |
259 | action SetMasked()
260 | {
261 | //bpf_skb_store_byte
262 | }
263 |
264 | action SetTunnel()
265 | {
266 | // bpf_set_tunnel_key
267 | }
268 |
269 | action Trunc()
270 | {
271 | // bpf_skb_change_tail
272 | }
273 |
274 | // a flow miss upcall sends the packet with its md
275 | // to the userspace (ovs-vswitchd), which will look
276 | // up OF tables and install flow entry into map
277 | action Upcall()
278 | {
279 | // bpf_perf_event_output(skb, &perf_events, len, msg, sizeof(msg));
280 | }
281 |
282 | // OVS datapath action dispatcher
283 | // Execute a fixed sequence of actions
284 | action OVS(bit<32> bitmap, action_md_t md) {
285 | // the bitmap is set by the control plane and indicates
286 | // which actions should be executed
287 | toRun = bitmap;
288 | // the action_md is the metadata for action to execute
289 | action_md = md;
290 | }
291 |
292 | table ovsTable() {
293 | key = { hdr.ipv4.srcAddr : exact; }
294 | actions = {
295 | OVS;
296 | Upcall; // Send to userspce ovs-vswitchd
297 | }
298 | default_action = Upcall; //NoAction;
299 | implementation = hash_table(1024);
300 | }
301 |
302 | apply {
303 | pass = true;
304 | toRun = 0;
305 |
306 | ovsTable.apply();
307 |
308 | // the sequece matters
309 | if ((toRun & OUTPUT_OFS) != 0) {
310 | Output();
311 | }
312 | if ((toRun & PUSHVLAN_OFS) != 0) {
313 | PushVlan();
314 | }
315 | if ((toRun & POPVLAN_OFS) != 0) {
316 | PopVlan();
317 | }
318 | if ((toRun & SETMASKED_OFS) != 0) {
319 | SetMasked();
320 | }
321 | if ((toRun & SETTUNEL_OFS) != 0) {
322 | SetTunnel();
323 | }
324 | if ((toRun & TRUNC_OFS) != 0) {
325 | Trunc();
326 | }
327 | }
328 | }
329 |
330 | // TODO: this should be argument to the new model ovs_ebpf_model()
331 | control Deparser(packet_out packet, in ovs_packet hdr) {
332 | apply {
333 | packet.emit(hdr.ethernet);
334 | packet.emit(hdr.vlan);
335 | packet.emit(hdr.ipv6);
336 | packet.emit(hdr.ipv4);
337 | packet.emit(hdr.icmp);
338 | packet.emit(hdr.udp);
339 | packet.emit(hdr.tcp);
340 | packet.emit(hdr.arp);
341 | }
342 | }
343 |
344 | // TODO: replace this with ovs_ebpf_model
345 | ebpfFilter(TopParser(), Ingress()) main;
346 |
--------------------------------------------------------------------------------
/p4c-xdp.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | #include "ir/ir.h"
22 | #include "lib/log.h"
23 | #include "lib/crash.h"
24 | #include "lib/exceptions.h"
25 | #include "lib/gc.h"
26 | #include "lib/nullstream.h"
27 |
28 | #include "backends/ebpf/midend.h"
29 | #include "backends/ebpf/ebpfOptions.h"
30 | #include "xdpBackend.h"
31 | #include "frontends/common/parseInput.h"
32 | #include "frontends/p4/frontend.h"
33 |
34 | void compile(EbpfOptions& options) {
35 | auto hook = options.getDebugHook();
36 | bool isv1 = options.langVersion == CompilerOptions::FrontendVersion::P4_14;
37 | if (isv1) {
38 | ::error(ErrorType::ERR_UNSUPPORTED, "This compiler only handles P4-16");
39 | return;
40 | }
41 | auto program = P4::parseP4File(options);
42 | if (::errorCount() > 0)
43 | return;
44 | P4::FrontEnd frontend;
45 | frontend.addDebugHook(hook);
46 | program = frontend.run(options, program);
47 | if (::errorCount() > 0)
48 | return;
49 |
50 | EBPF::MidEnd midend;
51 | midend.addDebugHook(hook);
52 | auto toplevel = midend.run(options, program);
53 | if (options.dumpJsonFile)
54 | JSONGenerator(*openFile(options.dumpJsonFile, true)) << program << std::endl;
55 | if (::errorCount() > 0)
56 | return;
57 |
58 | XDP::run_xdp_backend(options, toplevel, &midend.refMap, &midend.typeMap);
59 | }
60 |
61 | int main(int argc, char *const argv[]) {
62 | setup_gc_logging();
63 | setup_signals();
64 |
65 | AutoCompileContext autoEbpfContext(new EbpfContext);
66 | auto& options = EbpfContext::get().options();
67 | options.compilerVersion = "0.0.1";
68 |
69 | if (options.process(argc, argv) != nullptr)
70 | options.setInputFile();
71 | if (::errorCount() > 0)
72 | exit(1);
73 |
74 | compile(options);
75 |
76 | if (Log::verbose())
77 | std::cerr << "Done." << std::endl;
78 | return ::errorCount() > 0;
79 | }
80 |
--------------------------------------------------------------------------------
/p4include/xdp_model.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | /*
18 |
19 | This file describes a P4 architectural model called XDP. This model
20 | generates EBPF code that is run under the XDP (eXpress Data Path):
21 | https://www.iovisor.org/technology/xdp. We support two different architectures:
22 |
23 | - a packet filter, which is identical to the ebpfFilter architecture
24 | - a switch, which has a parser, control pipline and deparser
25 |
26 | */
27 |
28 | #ifndef _XDP_MODEL_P4
29 | #define _XDP_MODEL_P4
30 |
31 | #include
32 | #include // we continue to support the EBPF packet filter model
33 |
34 | enum xdp_action {
35 | XDP_ABORTED, // some fatal error occurred during processing;
36 | XDP_DROP, // packet should be dropped
37 | XDP_PASS, // packet should be passed to the Linux kernel
38 | XDP_TX, // packet should be resent out on the same interface
39 | XDP_REDIRECT // packet should be sent to a different interface
40 | }
41 |
42 | /* architectural model for a packet switch architecture */
43 | struct xdp_input {
44 | bit<32> input_port;
45 | }
46 |
47 | struct xdp_output {
48 | xdp_action output_action;
49 | bit<32> output_port; // output port for packet
50 | }
51 |
52 | // Rather ugly to have this very specific function here.
53 | extern bit<16> ebpf_ipv4_checksum(in bit<4> version, in bit<4> ihl, in bit<8> diffserv,
54 | in bit<16> totalLen, in bit<16> identification, in bit<3> flags,
55 | in bit<13> fragOffset, in bit<8> ttl, in bit<8> protocol,
56 | in bit<32> srcAddr, in bit<32> dstAddr);
57 |
58 | //Implements RFC 1624 (Incremental Internet Checksum)
59 | extern bit<16> csum_replace2(in bit<16> csum, // current csum
60 | in bit<16> old, // old value of the field
61 | in bit<16> new);
62 |
63 | extern bit<16> csum_replace4(in bit<16> csum,
64 | in bit<32> old,
65 | in bit<32> new);
66 |
67 | extern bit<32> BPF_PERF_EVENT_OUTPUT();
68 | // FIXME: use 64 bit
69 | extern bit<32> BPF_KTIME_GET_NS();
70 |
71 | parser xdp_parse(packet_in packet, out H headers);
72 | control xdp_switch(inout H headers, in xdp_input imd, out xdp_output omd);
73 | control xdp_deparse(in H headers, packet_out packet);
74 |
75 | package xdp(xdp_parse p, xdp_switch s, xdp_deparse d);
76 |
77 | #endif /* _XDP_MODEL_P4 */
78 |
--------------------------------------------------------------------------------
/run-bpf.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -x
3 | set -e
4 | # OVS BPF script for attaching to tc
5 | # filename: tmp.o
6 | # section name: _ebpf_filter
7 |
8 | DEV=enp0s16
9 |
10 | tc qdisc add dev $DEV clsact
11 | tc filter add dev $DEV ingress bpf da obj tmp.o sec _ebpf_filter verb
12 | #tc qdisc delete dev $DEV clsact
13 | #tc filter add dev $DEV egress bpf da obj tcbpf_ovs.o sec ovs_egress
14 |
15 | exit
16 | #tc qdisc delete dev $DEV clsact
17 | #tc filter add dev $DEV egress bpf da obj tcbpf_ovs.o exp /tmp/bpf-uds sec ovs_ingress
18 |
--------------------------------------------------------------------------------
/run-p4c-xdp.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # This program is invoked by make check-xdp to run
4 | # some xdp tests.
5 |
6 | folder="$1"
7 | verbose=0
8 | shift
9 |
10 | while getopts "bvf" opt; do
11 | case $opt in
12 | v)
13 | verbose=1
14 | ;;
15 | esac
16 | shift
17 | done
18 |
19 | file="$1"
20 |
21 | if [ $verbose -eq "1" ]; then
22 | echo $folder/build/p4c-xdp $file
23 | fi
24 | $folder/build/p4c-xdp -o tmp.c $file
25 |
--------------------------------------------------------------------------------
/target.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "target.h"
18 |
19 | namespace XDP {
20 |
21 | void XdpTarget::emitIncludes(Util::SourceCodeBuilder* builder) const {
22 | builder->append(
23 | "#define KBUILD_MODNAME \"xdptest\"\n"
24 | "#include \"ebpf_xdp.h\"\n"
25 | "\n");
26 | }
27 | } // namespace XDP
28 |
--------------------------------------------------------------------------------
/target.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #ifndef _EXTENSIONS_P4C_XDP_TARGET_H_
18 | #define _EXTENSIONS_P4C_XDP_TARGET_H_
19 |
20 | #include "backends/ebpf/target.h"
21 |
22 | namespace XDP {
23 |
24 | // Target XDP
25 | class XdpTarget : public EBPF::KernelSamplesTarget {
26 | public:
27 | XdpTarget() : KernelSamplesTarget(false, "XDP") {}
28 | void emitIncludes(Util::SourceCodeBuilder* builder) const override;
29 | cstring forwardReturnCode() const override { return "XDP_PASS"; }
30 | cstring dropReturnCode() const override { return "XDP_DROP"; }
31 | cstring abortReturnCode() const override { return "XDP_ABORTED"; }
32 | cstring sysMapPath() const override { return "/sys/fs/bpf/xdp/globals"; }
33 | };
34 |
35 | } // namespace XDP
36 |
37 | #endif /* _EXTENSIONS_P4C_XDP_TARGET_H_ */
38 |
--------------------------------------------------------------------------------
/test_ebpf_map.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Tool for accessing eBPF maps generated by P4
3 | * $gcc test_bpf_map.c libbpf.o -o test_bpf_map
4 | */
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include "libbpf.h"
17 |
18 | #define MAP_PATH "/sys/fs/bpf/tc/globals/match_action"
19 | typedef uint32_t u32;
20 |
21 | // FIXME: This is copied from ovs.c
22 | struct match_action_key {
23 | u32 field0;
24 | };
25 | enum match_action_actions {
26 | Reject,
27 | NoAction_1,
28 | };
29 | struct match_action_value {
30 | enum match_action_actions action;
31 | union {
32 | struct {
33 | u32 addr;
34 | } Reject;
35 | struct {
36 | } NoAction_1;
37 | } u;
38 | };
39 |
40 | int main(void)
41 | {
42 | int ret;
43 | int fd;
44 | struct match_action_key key;
45 | struct match_action_value value;
46 | struct in_addr inp;
47 |
48 | memset(&value, 0, sizeof(value));
49 | memset(&key, 0, sizeof(key));
50 | value.action = NoAction_1;
51 |
52 | ret = inet_aton("192.168.218.1", &inp);
53 | if (ret != 1)
54 | return 1;
55 | key.field0 = (u32)htonl(inp.s_addr);
56 |
57 | printf("=== Open BPF map: %s ===\n", MAP_PATH);
58 | fd = bpf_obj_get(MAP_PATH);
59 | if (fd < 0) {
60 | printf("BPF match_action map not loaded\n");
61 | return 1;
62 | }
63 |
64 | printf("=== Write to eBPF map ===\n");
65 | printf("key = %x value = %x\n", key.field0, value.action);
66 | ret = bpf_update_elem(fd, &key, &value, BPF_ANY);
67 | if (ret) {
68 | perror("error updating map element\n");
69 | return 1;
70 | }
71 |
72 | return 0;
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/tests/Makefile:
--------------------------------------------------------------------------------
1 | LLC ?= llc
2 | CLANG ?= clang
3 | CC= gcc
4 | CFLAGS=-g
5 | BPFOBJ= xdp1.o xdp2.o xdp3.o xdp4.o xdp5.o xdp6.o xdp7.o xdp8.o xdp9.o xdp10.o \
6 | xdp11.o xdp12.o xdp13.o xdp14.o xdp15.o xdp16.o
7 | BPFLOADER=bpfloader
8 | BPFLIB=../lib/
9 | #IFACE=enp0s16
10 | SRC=/root/p4c
11 | INCLUDE=-I ../p4include -I../../../backends/ebpf/runtime/
12 | P4C=p4c-xdp
13 |
14 | all: bpfloader $(BPFOBJ) verify_target_bpf
15 |
16 | bpfloader: load_and_verify.c
17 | make -C ../lib/
18 | $(CC) -I$(BPFLIB) $(BPFLIB)/libbpf.o $(BPFLIB)/bpf_load.o load_and_verify.c -lelf -o bpfloader
19 |
20 | # Verify LLVM compiler tools are available and bpf target is supported by llc
21 | .PHONY: verify_cmds verify_target_bpf $(CLANG) $(LLC)
22 |
23 | verify_cmds: $(CLANG) $(LLC)
24 | @for TOOL in $^ ; do \
25 | if ! (which -- "$${TOOL}" > /dev/null 2>&1); then \
26 | echo "*** ERROR: Cannot find LLVM tool $${TOOL}" ;\
27 | exit 1; \
28 | else \
29 | echo "pass verify_cmds:" \
30 | true; fi; \
31 | done
32 |
33 | verify_target_bpf: verify_cmds
34 | @if ! (${LLC} -march=bpf -mattr=help > /dev/null 2>&1); then \
35 | echo "*** ERROR: LLVM (${LLC}) does not support 'bpf' target" ;\
36 | echo " NOTICE: LLVM version >= 3.7.1 required" ;\
37 | exit 2; \
38 | else \
39 | echo "pass verify_target_bpf:" \
40 | true; fi
41 |
42 | # P4 generate .c
43 | # keep the intermediate .c file
44 | .PRECIOUS: %.c
45 | %.c: %.p4
46 | @if ! ($(P4C) --help > /dev/null 2>&1); then \
47 | echo "*** ERROR: Cannot find p4c-xdp"; \
48 | exit 1;\
49 | fi;
50 | $(P4C) --Werror $(INCLUDE) --target xdp -o $@ $<;
51 |
52 | # BPF program
53 | # do extra CLANG so first pass can return non-zero to shell and stop make
54 | %.o: %.c
55 | @$(CLANG) $(INCLUDE) \
56 | -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
57 | -Wno-compare-distinct-pointer-types \
58 | -Wno-gnu-variable-sized-type-not-at-end \
59 | -Wno-tautological-compare \
60 | -O2 -emit-llvm -g -c $< -o - > /dev/null
61 | $(CLANG) $(INCLUDE)\
62 | -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
63 | -Wno-compare-distinct-pointer-types \
64 | -Wno-gnu-variable-sized-type-not-at-end \
65 | -Wno-tautological-compare \
66 | -O2 -emit-llvm -g -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
67 | sudo ./$(BPFLOADER) $@ || true
68 |
69 | clean: clean_loader
70 | rm -f *.o *_ebpf.c xdp[1-9]*.[ch]
71 |
72 | clean_loader:
73 | rm -f bpfloader
74 |
75 | # For actually attaching BPF
76 | attach:
77 | ip link show $(IFACE); \
78 | for TOOL in $(BPFOBJ); do \
79 | ip link set dev $(IFACE) xdp obj $${TOOL} verb; \
80 | ip link set dev $(IFACE) xdp off; \
81 | done
82 |
--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------
1 | # p4c-xdp test cases
2 | To get started, simply run 'make'
3 |
4 | ## [xdp1.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp1.p4) (basic parser)
5 | - Parse:
6 | L2(Ethernet) and L3 (IPv4)
7 | - Action:
8 | Drop if not IP packet (the ARP will be dropped)
9 | - Deparse:
10 | None
11 |
12 | ## [xdp2.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp2.p4) (parser + deparser)
13 | - Parse:
14 | L2, L3 (IPv4), L4 (icmp)
15 | - Action:
16 | Drop if not IP packet (the ARP will be dropped)
17 | - Deparse:
18 | L2, L3 (IPv4), L4 (icmp)
19 |
20 | ## [xdp3.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp3.p4) (parser + lookup + deparser)
21 | - Parse:
22 | L2, L3 (IPv4)
23 | - Table:
24 | Ethernet.destination as key, action could be drop or pass
25 | ```C
26 | table dstmactable() {
27 | key = { hdr.ethernet.destination : exact; }
28 | actions = {
29 | Fallback_action;
30 | Drop_action;
31 | }
32 | ```
33 | - Deparse:
34 | L2, L3 (IPv4)
35 |
36 | ## [xdp4.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp4.p4) (parser + lookup with multiple fields as key + deparser)
37 | - Parse:
38 | L2, L3 (IPv4)
39 | - Table:
40 | Ethernet.{destination, protocl} as key, action could be drop or pass
41 | ```C
42 | table dstmactable() {
43 | key = { hdr.ethernet.destination : exact;
44 | hdr.ethernet.protocol: exact;}
45 | ```
46 | - Deparse:
47 | L2, L3 (IPv4)
48 |
49 | ## [xdp5.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp5.p4) (Test control plane)
50 | Test using user\_xdp5.c
51 | ```bash
52 | # gcc -I ../lib/ ../lib/libbpf.o user_xdp5.c -o xdp5
53 | # ./xdp5
54 | ```
55 | The function "initialize\_tables()" will set default to drop the packet.
56 | Then we populate the table by allowing the IP packet to execute Fallback\_action
57 |
58 | ## [xdp6.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp6.p4) (Add action metadata to set IP ttl)
59 | - Parse:
60 | L2, L3 (IPv4)
61 | - Table:
62 | ```C
63 | action SetTTL_action(action_md_t md)
64 | {
65 | hd.ipv4.ttl = md.ttl;
66 | xout.output_action = xdp_action.XDP_PASS;
67 | }
68 | ```
69 | - Deparse:
70 | L2, L3 (IPv4)
71 |
72 | ## [xdp7.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp7.p4) (SNAT and checksum update)
73 | - Parse L2, L3, and L4 to TCP
74 | - Modify source port and source IP
75 | - Return to Linux network stack (XDP\_PASS)
76 | - Exercise the csum\_replace{2,4} feature
77 |
78 | ## xdp8.p4
79 | Internal use for debugging
80 |
81 | ## [xdp9.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp9.p4) (ipv4 checksum recalc)
82 | - Parse:
83 | L2, L3 (IPv4), L4 (TCP, UDP, ICMP)
84 | - Table:
85 |
86 | ```C
87 | action Fallback_action()
88 | {
89 | hd.ipv4.ttl = 4;
90 | hd.ipv4.hdrChecksum = ebpf_ipv4_checksum(
91 | hd.ipv4.version, hd.ipv4.ihl, hd.ipv4.diffserv,
92 | ```
93 | - Deparse:
94 | L2, L3
95 |
96 | ## [xdp10.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp10.p4) (Counter)
97 | Count the number of received ipv4 packets for a particular
98 | IPv4 destination address. A BPF hashmap is created for key
99 | equals ipv4.dstAddr, value equals u32 counter.
100 | ```C
101 | apply {
102 | if (hd.ipv4.isValid())
103 | {
104 | counters.increment((bit<32>)hd.ipv4.dstAddr);
105 | }
106 | ```
107 | Compile the user\_xdp10.c and it will dump the counter
108 |
109 | ## [xdp11.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp11.p4) (Swap ethernet src and dst, then XDP\_TX)
110 | - Try to do similar feature as kernel's samples/bpf/xdp2\_kern.c
111 | - [demo video](https://youtu.be/On7hEJ6bPVU)
112 | ```C
113 | bit<48> tmp;
114 | apply {
115 | if (hd.ipv4.isValid())
116 | {
117 | tmp = hd.ethernet.destination;
118 | hd.ethernet.destination = hd.ethernet.source;
119 | hd.ethernet.source = tmp;
120 | }
121 | ```
122 | ## [xdp12.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp12.p4)
123 | - Parse IPv4/IPv6 ping
124 | - Update ipv4 statistics, and return XDP\_PASS
125 | - Drop ipv6 ping, and return XDP\_DROP
126 | - [demo video](https://youtu.be/vlp1MzWVOc8)
127 |
128 | ## [xdp13.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp13.p4) (Multiple Tables, Single Action)
129 | - Parse L2, L3, L4 (icmp)
130 | - Create and lookup L2, L3, L4 tables
131 | - Default will drop ipv4 ICMP
132 | - XDP\_PASS for the rest of the traffic
133 |
134 | ## [xdp14.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp14.p4) (Multiple Actions, Single Table)
135 | - Parse L2, L3, L4 (icmp)
136 | - Create 1 table with value = bitmap of actions to execute
137 |
138 | ## [xdp15.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp15.p4) (Encapsulation)
139 | - unconditionally append a fixed customized header in front of Ethernet header
140 | ```C
141 | /* encap my own header */
142 | header myhdr_t {
143 | bit<32> id;
144 | bit<32> timestamp;
145 | }
146 | ```
147 | then at deparser, emit it before ethernet header
148 | ```C
149 | control Deparser(in Headers hdrs, packet_out packet) {
150 | apply {
151 | packet.emit(hdrs.myhdr);
152 | packet.emit(hdrs.ethernet);
153 | }
154 | }
155 | ```
156 | ## [xdp16.p4](https://github.com/williamtu/p4c-xdp/blob/master/tests/xdp16.p4) (Encap and BPF XDP helpers)
157 | - [demo video](https://youtu.be/TibGxCXPNVc)
158 | ## TODO
159 |
160 |
--------------------------------------------------------------------------------
/tests/ebpf_headers.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2013-present Barefoot Networks, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #ifndef _EBPF_HEADERS_
18 | #define _EBPF_HEADERS_
19 |
20 | @ethernetaddress typedef bit<48> EthernetAddress;
21 | @ipv4address typedef bit<32> IPv4Address;
22 |
23 | // standard Ethernet header
24 | header Ethernet_h
25 | {
26 | EthernetAddress dstAddr;
27 | EthernetAddress srcAddr;
28 | bit<16> etherType;
29 | }
30 |
31 | // IPv4 header without options
32 | header IPv4_h {
33 | bit<4> version;
34 | bit<4> ihl;
35 | bit<8> diffserv;
36 | bit<16> totalLen;
37 | bit<16> identification;
38 | bit<3> flags;
39 | bit<13> fragOffset;
40 | bit<8> ttl;
41 | bit<8> protocol;
42 | bit<16> hdrChecksum;
43 | IPv4Address srcAddr;
44 | IPv4Address dstAddr;
45 | }
46 |
47 | #endif
48 |
--------------------------------------------------------------------------------
/tests/ebpf_xdp.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2018 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | /*
18 | * This file contains all functions and definitions necessary for the xdp target C code to compile. It must be included with any file generated by the p4c-xdp compiler.
19 | */
20 |
21 | #ifndef __BPF_HELPERS_H
22 | #define __BPF_HELPERS_H
23 |
24 | #include "ebpf_kernel.h"
25 |
26 | /* xdp descriptor similar to sk_buff */
27 | #ifdef SK_BUFF
28 | #undef SK_BUFF
29 | #endif
30 | #define SK_BUFF struct xdp_md
31 |
32 | #ifdef load_dword
33 | #undef load_dword
34 | #endif
35 |
36 | #define load_dword(data, b) (*(u64 *)((u8*)(data) + (b))) << 16
37 |
38 |
39 |
40 | #endif
41 |
--------------------------------------------------------------------------------
/tests/empty.stf:
--------------------------------------------------------------------------------
1 | # empty stf file, used to just validate the code produced by p4c-xdp
2 |
--------------------------------------------------------------------------------
/tests/load_and_verify.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #include "bpf_load.h"
28 | #include "libbpf.h"
29 |
30 | int main(int ac, char **argv)
31 | {
32 | char filename[256];
33 | struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
34 |
35 | snprintf(filename, sizeof(filename), "%s", argv[1]);
36 |
37 | if (setrlimit(RLIMIT_MEMLOCK, &r)) {
38 | perror("setrlimit(RLIMIT_MEMLOCK, RLIM_INFINITY)");
39 | return 1;
40 | }
41 |
42 | if (ac != 2) {
43 | printf("usage: %s BPF.o\n", argv[0]);
44 | return 1;
45 | }
46 |
47 | if (load_bpf_file(filename)) {
48 | printf("FAILED: %s", bpf_log_buf);
49 | return 1;
50 | }
51 | printf("PASS\n");
52 |
53 | return 0;
54 | }
55 |
--------------------------------------------------------------------------------
/tests/user_xdp10.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Tool for accessing eBPF maps generated by P4, at tests/
3 | * gcc -I ../lib/ ../lib/libbpf.o user_xdp10.c -o xdp10
4 | */
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include "libbpf.h"
18 |
19 | #include "xdp10.h"
20 |
21 | #define TABLE "/dstmactable"
22 | #define STATS "/counters"
23 |
24 | int main(void)
25 | {
26 | int ret;
27 | int fd, i;
28 | struct in_addr addr;
29 | counters_key key;
30 | counters_value value;
31 |
32 | inet_aton("10.2.2.9", &addr);
33 | memcpy(&key, &addr, 4);
34 | key = ntohl(key);
35 |
36 | printf("=== Open BPF map: %s ===\n", MAP_PATH STATS);
37 | fd = bpf_obj_get(MAP_PATH STATS);
38 | if (fd < 0) {
39 | printf("BPF map %s not loaded\n", MAP_PATH STATS);
40 | exit(1);
41 | }
42 |
43 | /* populate the match-action table */
44 | for (i = 0; i < 10; i++) {
45 | printf("=== Lookup to eBPF map ===\n");
46 | ret = bpf_lookup_elem(fd, &key, &value);
47 | if (!ret)
48 | printf("counter = %d\n", value);
49 | sleep(1);
50 | }
51 | close(fd);
52 | return 0;
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/tests/user_xdp5.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Tool for accessing eBPF maps generated by P4, at tests/
3 | * gcc -I ../lib/ ../lib/libbpf.o user_xdp5.c
4 | */
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include "libbpf.h"
18 |
19 | #define CONTROL_PLANE 1
20 | #include "xdp5.h"
21 |
22 | // we might want to put this into header
23 | #define TABLE "/dstmactable"
24 |
25 | int main(void)
26 | {
27 | int ret;
28 | int fd;
29 | struct dstmactable_key key;
30 | struct dstmactable_value value;
31 |
32 | /* populate the default table */
33 | initialize_tables();
34 |
35 | value.action = Fallback_action;
36 | key.field0 = 0x800; // IP packet
37 |
38 | printf("=== Open BPF map: %s ===\n", MAP_PATH TABLE);
39 | fd = bpf_obj_get(MAP_PATH TABLE);
40 | if (fd < 0) {
41 | printf("BPF map %s not loaded\n", MAP_PATH TABLE);
42 | exit(1);
43 | }
44 |
45 | /* populate the match-action table */
46 | printf("=== Write to eBPF map ===\n");
47 | printf("key = %x value = %x\n", key.field0, value.action);
48 | ret = bpf_update_elem(fd, &key, &value, BPF_ANY);
49 | if (ret) {
50 | perror("error updating map element\n");
51 | exit(1);
52 | }
53 |
54 | close(fd);
55 | return 0;
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/tests/xdp.p4:
--------------------------------------------------------------------------------
1 | #include "xdp_model.p4"
2 |
3 | struct ovs_packet {}
4 |
5 | parser Parser(packet_in packet, out ovs_packet hdr) {
6 | state start {
7 | hdr = {};
8 | transition accept;
9 | }
10 | }
11 |
12 | control Ingress(inout ovs_packet hdr, in xdp_input xin, out xdp_output xout) {
13 | apply {
14 | xout.output_port = 0;
15 | xout.output_action = xdp_action.XDP_DROP;
16 | }
17 | }
18 |
19 | control Deparser(in ovs_packet hdrs, packet_out packet) {
20 | apply {
21 | ;
22 | }
23 | }
24 |
25 | xdp(Parser(), Ingress(), Deparser()) main;
26 |
--------------------------------------------------------------------------------
/tests/xdp.stf:
--------------------------------------------------------------------------------
1 | # bit<32> A bit<32> B
2 | # In the output B = (A + 10)
3 |
4 |
5 | packet 0 00000000 00000000 00000000 00000000 00000000 ABCDEF01
6 |
7 | packet 0 001b1700 0130b881 98b7aeb7 08004500 00344a6f 40004006 53920a01 98453212 c86acf2c 01bbd0fa 585c4ccc b2ac8010 0353c314 00000101 080a0192 463911a0 c06f
8 |
9 |
10 | packet 0 00000000 00000000 00000000 00000000 00000000 00010000
11 | packet 0 00000000 00000000 00000000 00000000 00000000 00011000
12 |
13 | packet 1 001b1700 0130b881 98b7aeb7 08004500 00344a6f 40004006 53920a01 98453212 d86acf2c 01bbd0fa 585c4ccc b2ac8010 0353c314 00000101 080a0192 463911a0 c06f
14 |
--------------------------------------------------------------------------------
/tests/xdp1.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | struct Headers {
41 | Ethernet ethernet;
42 | IPv4 ipv4;
43 | }
44 |
45 | parser Parser(packet_in packet, out Headers hd) {
46 | state start {
47 | packet.extract(hd.ethernet);
48 | transition select(hd.ethernet.protocol) {
49 | 16w0x800: parse_ipv4;
50 | default: accept;
51 | }
52 | }
53 |
54 | state parse_ipv4 {
55 | packet.extract(hd.ipv4);
56 | transition accept;
57 | }
58 | }
59 |
60 | control Ingress(inout Headers hdr, in xdp_input xin, out xdp_output xout) {
61 | apply {
62 | xout.output_port = 0;
63 | xout.output_action = (hdr.ethernet.protocol != 0x800) ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
64 | }
65 | }
66 |
67 | control Deparser(in Headers hdrs, packet_out packet) {
68 | apply {
69 | packet.emit(hdrs.ethernet);
70 | packet.emit(hdrs.ipv4);
71 | }
72 | }
73 |
74 | xdp(Parser(), Ingress(), Deparser()) main;
75 |
--------------------------------------------------------------------------------
/tests/xdp1.stf:
--------------------------------------------------------------------------------
1 | # bit<32> A bit<32> B
2 | # In the output B = (A + 10)
3 |
4 |
5 | packet 0 00000000 00000000 00000000 00000000 00000000 ABCDEF01
6 |
7 |
8 | # | ethernet header | IPv4 header | TCP header
9 | # dstAddr srcAddr type| VL len id ttl csum src dst | sp dp len csum
10 | packet 0 001b17000130 b88198b7aeb7 0800 45 00 0034 4a6f 4000 40 06 5392 0a019845 3212c86a cf2c 01bb d0fa 585c4ccc b2ac8010 0353 c314 00000101 080a0192 463911a0 c06f
11 | expect 0 001b17000130 b88198b7aeb7 0800 45 00 0034 4a6f 4000 40 06 5392 0a019845 3212c86a cf2c 01bbd0fa 585c4ccc b2ac8010 0353c314 00000101 080a0192 463911a0 c06f
12 |
13 | packet 0 00000000 00000000 00000000 00000000 00000000 00010000
14 |
15 | packet 0 00000000 00000000 00000000 00000000 00000000 00011000
--------------------------------------------------------------------------------
/tests/xdp10.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> source;
21 | bit<48> destination;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | struct Headers {
41 | Ethernet ethernet;
42 | IPv4 ipv4;
43 | }
44 |
45 | parser Parser(packet_in packet, out Headers hd) {
46 | state start {
47 | packet.extract(hd.ethernet);
48 | transition select(hd.ethernet.protocol) {
49 | 16w0x800: parse_ipv4;
50 | default: accept;
51 | }
52 | }
53 | state parse_ipv4 {
54 | packet.extract(hd.ipv4);
55 | transition select(hd.ipv4.protocol) {
56 | default: accept;
57 | }
58 | }
59 | }
60 |
61 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
62 | bool xoutdrop = false;
63 | CounterArray(32w10, true) counters;
64 |
65 | action SetTTL_action()
66 | {
67 | hd.ipv4.ttl = 4;
68 | xoutdrop = false;
69 | }
70 |
71 | action Fallback_action()
72 | {
73 | xoutdrop = false;
74 | }
75 |
76 | action Drop_action()
77 | {
78 | xoutdrop = true;
79 | }
80 |
81 | table dstmactable {
82 | key = { hd.ipv4.dstAddr : exact; }
83 | actions = {
84 | SetTTL_action;
85 | Fallback_action;
86 | Drop_action;
87 | }
88 | default_action = SetTTL_action;
89 | implementation = hash_table(64);
90 | }
91 |
92 | apply {
93 | if (hd.ipv4.isValid())
94 | {
95 | counters.increment((bit<32>)hd.ipv4.dstAddr);
96 | }
97 | dstmactable.apply();
98 | xout.output_port = 0;
99 | xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
100 | }
101 | }
102 |
103 | control Deparser(in Headers hdrs, packet_out packet) {
104 | apply {
105 | packet.emit(hdrs.ethernet);
106 | packet.emit(hdrs.ipv4);
107 | }
108 | }
109 |
110 | xdp(Parser(), Ingress(), Deparser()) main;
111 |
--------------------------------------------------------------------------------
/tests/xdp11.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> source;
21 | bit<48> destination;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | struct Headers {
41 | Ethernet ethernet;
42 | IPv4 ipv4;
43 | }
44 |
45 | parser Parser(packet_in packet, out Headers hd) {
46 | state start {
47 | packet.extract(hd.ethernet);
48 | transition select(hd.ethernet.protocol) {
49 | 16w0x800: parse_ipv4;
50 | default: accept;
51 | }
52 | }
53 | state parse_ipv4 {
54 | packet.extract(hd.ipv4);
55 | transition select(hd.ipv4.protocol) {
56 | default: accept;
57 | }
58 | }
59 | }
60 |
61 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
62 |
63 | bit<48> tmp;
64 | xdp_action xact = xdp_action.XDP_PASS;
65 |
66 | apply {
67 | if (hd.ipv4.isValid())
68 | {
69 | tmp = hd.ethernet.destination;
70 | hd.ethernet.destination = hd.ethernet.source;
71 | hd.ethernet.source = tmp;
72 | xact = xdp_action.XDP_TX;
73 | }
74 | xout.output_port = 0;
75 | xout.output_action = xact;
76 | }
77 | }
78 |
79 | control Deparser(in Headers hdrs, packet_out packet) {
80 | apply {
81 | packet.emit(hdrs.ethernet);
82 | packet.emit(hdrs.ipv4);
83 | }
84 | }
85 |
86 | xdp(Parser(), Ingress(), Deparser()) main;
87 |
--------------------------------------------------------------------------------
/tests/xdp12.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | header IPv6 {
41 | bit<4> version;
42 | bit<8> trafficClass;
43 | bit<20> flowLabel;
44 | bit<16> payloadLen;
45 | bit<8> nextHdr;
46 | bit<8> hopLimit;
47 | bit<128> srcAddr;
48 | bit<128> dstAddr;
49 | }
50 |
51 | struct Headers {
52 | Ethernet ethernet;
53 | IPv4 ipv4;
54 | IPv6 ipv6;
55 | }
56 |
57 | parser Parser(packet_in packet, out Headers hd) {
58 | state start {
59 | packet.extract(hd.ethernet);
60 | transition select(hd.ethernet.protocol) {
61 | 16w0x0800: parse_ipv4;
62 | 16w0x86dd: parse_ipv6;
63 | default: accept;
64 | }
65 | }
66 |
67 | state parse_ipv4 {
68 | packet.extract(hd.ipv4);
69 | transition accept;
70 | }
71 | state parse_ipv6 {
72 | packet.extract(hd.ipv6);
73 | transition accept;
74 | }
75 | }
76 |
77 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
78 |
79 | bool xoutdrop = false;
80 | CounterArray(32w10, true) counters;
81 |
82 | apply {
83 | if (hd.ipv4.isValid())
84 | {
85 | counters.increment((bit<32>)hd.ipv4.dstAddr);
86 | xoutdrop = false;
87 | }
88 | if (hd.ipv6.isValid())
89 | {
90 | xoutdrop = true;
91 | }
92 | xout.output_port = 0;
93 | xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
94 | }
95 | }
96 |
97 | control Deparser(in Headers hdrs, packet_out packet) {
98 | apply {
99 | packet.emit(hdrs.ethernet);
100 | packet.emit(hdrs.ipv4);
101 | packet.emit(hdrs.ipv6);
102 | }
103 | }
104 |
105 | xdp(Parser(), Ingress(), Deparser()) main;
106 |
--------------------------------------------------------------------------------
/tests/xdp13.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | header icmp_t {
41 | bit<16> typeCode;
42 | bit<16> hdrChecksum;
43 | }
44 |
45 | struct Headers {
46 | Ethernet ethernet;
47 | IPv4 ipv4;
48 | icmp_t icmp;
49 | }
50 |
51 | parser Parser(packet_in packet, out Headers hd) {
52 | state start {
53 | packet.extract(hd.ethernet);
54 | transition select(hd.ethernet.protocol) {
55 | 16w0x800: parse_ipv4;
56 | default: accept;
57 | }
58 | }
59 | state parse_ipv4 {
60 | packet.extract(hd.ipv4);
61 | transition select(hd.ipv4.protocol) {
62 | 8w1: parse_icmp;
63 | default: accept;
64 | }
65 | }
66 | state parse_icmp {
67 | packet.extract(hd.icmp);
68 | transition accept;
69 | }
70 | }
71 |
72 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
73 |
74 | xdp_action xact = xdp_action.XDP_PASS;
75 |
76 | action l2_Fallback_action() { xact = xdp_action.XDP_PASS; }
77 | action l2_Drop_action() { xact = xdp_action.XDP_DROP; }
78 |
79 | table l2table {
80 | key = { hd.ethernet.protocol : exact; }
81 | actions = {
82 | l2_Fallback_action;
83 | l2_Drop_action;
84 | }
85 | default_action = l2_Fallback_action;
86 | implementation = hash_table(64);
87 | }
88 |
89 | action l3_Fallback_action() { xact = xdp_action.XDP_PASS; }
90 | action l3_Drop_action() { xact = xdp_action.XDP_DROP; }
91 | table l3table {
92 | key = { hd.ipv4.dstAddr : exact; }
93 | actions = {
94 | l3_Fallback_action;
95 | l3_Drop_action;
96 | }
97 | default_action = l3_Fallback_action;
98 | implementation = hash_table(64);
99 | }
100 |
101 | action l4_Fallback_action() { xact = xdp_action.XDP_PASS; }
102 | action l4_Drop_action() { xact = xdp_action.XDP_DROP; }
103 | table l4table {
104 | key = {hd.icmp.typeCode : exact; }
105 | actions = {
106 | l4_Drop_action; // Default Drop
107 | l4_Fallback_action;
108 | }
109 | default_action = l4_Drop_action;
110 | implementation = hash_table(64);
111 | }
112 |
113 | apply {
114 | l2table.apply();
115 | l3table.apply();
116 | if (hd.icmp.isValid()) {
117 | l4table.apply();
118 | }
119 | xout.output_port = 0;
120 | xout.output_action = xact;
121 | }
122 | }
123 |
124 | control Deparser(in Headers hdrs, packet_out packet) {
125 | apply {
126 | ;
127 | }
128 | }
129 |
130 | xdp(Parser(), Ingress(), Deparser()) main;
131 |
--------------------------------------------------------------------------------
/tests/xdp14.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | #define OUTPUT_OFS (1<<0)
20 | #define PUSHVLAN_OFS (1<<1)
21 | #define SETTUNNEL_OFS (1<<2)
22 |
23 | header Ethernet {
24 | bit<48> destination;
25 | bit<48> source;
26 | bit<16> protocol;
27 | }
28 |
29 | header IPv4 {
30 | bit<4> version;
31 | bit<4> ihl;
32 | bit<8> diffserv;
33 | bit<16> totalLen;
34 | bit<16> identification;
35 | bit<3> flags;
36 | bit<13> fragOffset;
37 | bit<8> ttl;
38 | bit<8> protocol;
39 | bit<16> hdrChecksum;
40 | bit<32> srcAddr;
41 | bit<32> dstAddr;
42 | }
43 |
44 | header icmp_t {
45 | bit<16> typeCode;
46 | bit<16> hdrChecksum;
47 | }
48 |
49 | struct Headers {
50 | Ethernet ethernet;
51 | IPv4 ipv4;
52 | icmp_t icmp;
53 | }
54 |
55 | struct output_md_t {
56 | bit<32> port; /* ifindex */
57 | }
58 |
59 | struct pushvlan_md_t {
60 | bit<16> tci;
61 | bit<16> proto;
62 | }
63 |
64 | struct settunnel_md_t {
65 | bit<32> ip_dst;
66 | bit<32> ip_src;
67 | bit<64> tun_id;
68 | bit<16> flags;
69 | }
70 |
71 | struct action_md_t {
72 | output_md_t output;
73 | pushvlan_md_t pushvlan;
74 | settunnel_md_t settunnel;
75 | }
76 |
77 | parser Parser(packet_in packet, out Headers hd) {
78 | state start {
79 | packet.extract(hd.ethernet);
80 | transition select(hd.ethernet.protocol) {
81 | 16w0x800: parse_ipv4;
82 | default: accept;
83 | }
84 | }
85 | state parse_ipv4 {
86 | packet.extract(hd.ipv4);
87 | transition select(hd.ipv4.protocol) {
88 | 8w1: parse_icmp;
89 | default: accept;
90 | }
91 | }
92 | state parse_icmp {
93 | packet.extract(hd.icmp);
94 | transition accept;
95 | }
96 | }
97 |
98 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
99 |
100 | bit<32> outport = 0;
101 | bit<32> bitmap = 0;
102 | action_md_t action_md;
103 | xdp_action xact = xdp_action.XDP_PASS;
104 |
105 | action output() {
106 | outport = action_md.output.port;
107 | xact = xdp_action.XDP_DROP;
108 | }
109 | action push_vlan() {
110 | bit<16> tci = action_md.pushvlan.tci;
111 | bit<16> proto = action_md.pushvlan.proto;
112 | // bpf_skb_vlan_push not support in XDP
113 | // how to inform deparser?
114 | }
115 | action set_tunnel() {
116 | bit<32> dst = action_md.settunnel.ip_dst;
117 | bit<32> src = action_md.settunnel.ip_src;
118 | bit<64> tun_id = action_md.settunnel.tun_id;
119 | bit<16> flags = action_md.settunnel.flags;
120 | // bpf_skb_set_tunnel_key not support in XDP
121 | // how to pass tunnel key to deparser?
122 | }
123 | action fallback() {
124 | xact = xdp_action.XDP_PASS;
125 | }
126 |
127 | action exec_action(bit<32> __bitmap, action_md_t md) {
128 | bitmap = __bitmap;
129 | action_md = md;
130 | }
131 |
132 | table action_bitmap {
133 | key = { hd.ethernet.protocol : exact; }
134 | actions = {
135 | fallback;
136 | exec_action;
137 | }
138 | default_action = fallback;
139 | implementation = hash_table(64);
140 | }
141 |
142 | apply {
143 | action_md.output.port = 0;
144 | action_bitmap.apply();
145 |
146 | /* Execute 3 actions in order, if its bit is set */
147 | if ((bitmap & PUSHVLAN_OFS) != 0) {
148 | push_vlan();
149 | }
150 | if ((bitmap & SETTUNNEL_OFS) != 0) {
151 | set_tunnel();
152 | }
153 | if ((bitmap & OUTPUT_OFS) != 0) {
154 | output();
155 | }
156 | xout.output_port = outport;
157 | xout.output_action = xact;
158 | }
159 | }
160 |
161 | control Deparser(in Headers hdrs, packet_out packet) {
162 | apply {
163 | ; // We do not change packet content
164 | }
165 | }
166 |
167 | xdp(Parser(), Ingress(), Deparser()) main;
168 |
--------------------------------------------------------------------------------
/tests/xdp15.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | /* encap my own header */
26 | header myhdr_t {
27 | bit<32> id;
28 | bit<32> timestamp;
29 | }
30 |
31 | struct Headers {
32 | Ethernet ethernet;
33 | myhdr_t myhdr;
34 | }
35 |
36 | parser Parser(packet_in packet, out Headers hd) {
37 | state start {
38 | packet.extract(hd.ethernet);
39 | transition select(hd.ethernet.protocol) {
40 | default: accept;
41 | }
42 | }
43 | }
44 |
45 | control Ingress(inout Headers hdr, in xdp_input xin, out xdp_output xout) {
46 |
47 | apply {
48 | hdr.myhdr.id = 0xfefefefe; // get ID from map or else
49 | hdr.myhdr.timestamp = 0x12345678;
50 | hdr.myhdr.setValid();
51 | xout.output_port = 0;
52 | xout.output_action = xdp_action.XDP_PASS;
53 | }
54 | }
55 |
56 | control Deparser(in Headers hdrs, packet_out packet) {
57 | apply {
58 | packet.emit(hdrs.myhdr);
59 | packet.emit(hdrs.ethernet);
60 | }
61 | }
62 |
63 | xdp(Parser(), Ingress(), Deparser()) main;
64 |
--------------------------------------------------------------------------------
/tests/xdp16.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | // your customized header
26 | header myhdr_t {
27 | bit<32> id;
28 | bit<32> ts; // timestamp
29 | }
30 |
31 | struct Headers {
32 | myhdr_t myhdr;
33 | Ethernet ethernet;
34 | }
35 |
36 | parser Parser(packet_in packet, out Headers hd) {
37 | state start {
38 | packet.extract(hd.ethernet);
39 | transition select(hd.ethernet.protocol) {
40 | default: accept;
41 | }
42 | }
43 | }
44 |
45 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
46 |
47 | bool xoutdrop = false;
48 | action TS_action()
49 | {
50 | // Get the timestamp by calling BPF helper
51 | hd.myhdr.ts = BPF_KTIME_GET_NS();
52 | hd.myhdr.id = 0xfefefefe;
53 | xoutdrop = false;
54 | }
55 |
56 | action Drop_action()
57 | {
58 | // Send the packet to userspace before drop
59 | BPF_PERF_EVENT_OUTPUT();
60 | xoutdrop = true;
61 | }
62 |
63 | table dstmactable {
64 | key = { hd.ethernet.protocol : exact; }
65 | actions = {
66 | TS_action;
67 | Drop_action;
68 | }
69 | default_action = TS_action;
70 | implementation = hash_table(64);
71 | }
72 |
73 | apply {
74 | dstmactable.apply();
75 | // set valid of myhdr so deparser will emit
76 | hd.myhdr.setValid();
77 | xout.output_port = 0;
78 | xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
79 | }
80 | }
81 |
82 | control Deparser(in Headers hdrs, packet_out packet) {
83 | apply {
84 | // prepend the customized header in the front
85 | packet.emit(hdrs.myhdr);
86 | packet.emit(hdrs.ethernet);
87 | }
88 | }
89 |
90 | xdp(Parser(), Ingress(), Deparser()) main;
91 |
--------------------------------------------------------------------------------
/tests/xdp17.p4:
--------------------------------------------------------------------------------
1 | #include "xdp_model.p4"
2 |
3 | header some {
4 | bit<32> b;
5 | }
6 |
7 | struct ovs_packet {
8 | some some;
9 | }
10 |
11 | parser Parser(packet_in packet, out ovs_packet hdr) {
12 | state start {
13 | hdr = { { 0 } };
14 | transition accept;
15 | }
16 | }
17 |
18 | control Ingress(inout ovs_packet hdr, in xdp_input xin, out xdp_output xout) {
19 | apply {
20 | xout.output_port = 0;
21 | xout.output_action = xdp_action.XDP_DROP;
22 | }
23 | }
24 |
25 | control Deparser(in ovs_packet hdrs, packet_out packet) {
26 | apply {
27 | if (hdrs.some.isValid() && hdrs.some.b != 0)
28 | packet.emit(hdrs.some);
29 | }
30 | }
31 |
32 | xdp(Parser(), Ingress(), Deparser()) main;
33 |
--------------------------------------------------------------------------------
/tests/xdp2.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | header icmp_h {
41 | bit<8> type_;
42 | bit<8> code;
43 | bit<16> hdrChecksum;
44 | }
45 |
46 | struct Headers {
47 | Ethernet ethernet;
48 | IPv4 ipv4;
49 | icmp_h icmp;
50 | }
51 |
52 | parser Parser(packet_in packet, out Headers hd) {
53 | state start {
54 | packet.extract(hd.ethernet);
55 | transition select(hd.ethernet.protocol) {
56 | 16w0x800: parse_ipv4;
57 | default: accept;
58 | }
59 | }
60 |
61 | state parse_ipv4 {
62 | packet.extract(hd.ipv4);
63 | transition select(hd.ipv4.protocol) {
64 | 8w0x1: parse_icmp;
65 | default: reject;
66 | }
67 | }
68 |
69 | state parse_icmp {
70 | packet.extract(hd.icmp);
71 | transition accept;
72 | }
73 | }
74 |
75 | control Ingress(inout Headers hdr, in xdp_input xin, out xdp_output xout) {
76 | apply {
77 | xout.output_port = 0;
78 | xout.output_action = hdr.ethernet.protocol != 0x800 ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
79 | }
80 | }
81 |
82 | control Deparser(in Headers hdrs, packet_out packet) {
83 | apply {
84 | packet.emit(hdrs.ethernet);
85 | packet.emit(hdrs.ipv4);
86 | packet.emit(hdrs.icmp);
87 | }
88 | }
89 |
90 | xdp(Parser(), Ingress(), Deparser()) main;
91 |
--------------------------------------------------------------------------------
/tests/xdp2.stf:
--------------------------------------------------------------------------------
1 | # bit<32> A bit<32> B
2 | # In the output B = (A + 10)
3 |
4 |
5 | packet 0 00000000 00000000 00000000 00000000 00000000 ABCDEF01
6 |
7 |
8 | # | ethernet header | IPv4 header | TCP header
9 | # dstAddr srcAddr type| VL len id ttl csum src dst | sp dp len csum
10 | packet 0 001b17000130 b88198b7aeb7 0800 45 00 0034 4a6f 4000 40 06 5392 0a019845 3212c86a cf2c 01bb d0fa 585c4ccc b2ac8010 0353 c314 00000101 080a0192 463911a0 c06f
11 |
12 | packet 0 00000000 00000000 00000000 00000000 00000000 00010000
13 |
14 | packet 0 00000000 00000000 00000000 00000000 00000000 00011000
15 |
16 | # | ethernet header | IPv4 header | ICMP header
17 | # dstAddr srcAddr type| VL len id ttl csum src dst |type
18 | packet 0 001b17000130 b88198b7aeb7 0800 45 00 0054 6dde 4000 40 01 fcf0 0a01b5c9 08080808 0800 384c 34fd 0001 2bc96d5b 0000 0000 2ebe 0400 0000 0000 10111213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
19 | expect 0 001b17000130 b88198b7aeb7 0800 45 00 0054 6dde 4000 40 01 fcf0 0a01b5c9 08080808 0800 384c 34fd 0001 2bc96d5b 0000 0000 2ebe 0400 0000 0000 10111213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
20 |
21 | packet 1 b88198b7aeb7 001b17000130 0800 45 00 0054 c67e 0000 79 01 ab50 08080808 0a01b5c9 0000 404c 34fd0001 2bc9 6d5b 0000 0000 2ebe 0400 00000000 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
22 | expect 1 b88198b7aeb7 001b17000130 0800 45 00 0054 c67e 0000 79 01 ab50 08080808 0a01b5c9 0000 404c 34fd0001 2bc9 6d5b 0000 0000 2ebe 0400 00000000 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
23 |
24 | packet 0 001b17000130 b88198b7aeb7 0800 45 00 0054 6dde 4000 40 01 fcf0 0a01b5c9 08080808 0800 4b46 34fd 0002 2cc9 6d5b 00000000 1ac3 0400 0000 0000 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
25 | expect 0 001b17000130 b88198b7aeb7 0800 45 00 0054 6dde 4000 40 01 fcf0 0a01b5c9 08080808 0800 4b46 34fd 0002 2cc9 6d5b 00000000 1ac3 0400 0000 0000 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
26 |
27 | packet 2 b88198b7aeb7 001b17000130 0800 45 00 0054 c67e 0000 79 01 ab50 08080808 0a01b5c9 0000 5346 34fd 0002 2cc9 6d5b 00000000 1ac3 0400 0000 0000 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
28 | expect 2 b88198b7aeb7 001b17000130 0800 45 00 0054 c67e 0000 79 01 ab50 08080808 0a01b5c9 0000 5346 34fd 0002 2cc9 6d5b 00000000 1ac3 0400 0000 0000 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
29 |
30 | packet 0 001b17000130 b88198b7aeb7 0800 45 00 0054 6dde 4000 40 01 fcf0 0a01b5c9 08080808 0800 8940 34fd 0003 2dc96d5b 0000 0000 dbc7 0400 0000 0000 1011 1213 14151617 1819 1a1b 1c1d 1e1f 20212223 2425 2627 2829 2a2b 2c2d 2e2f 30313233 3435 3637
31 | expect 0 001b17000130 b88198b7aeb7 0800 45 00 0054 6dde 4000 40 01 fcf0 0a01b5c9 08080808 0800 8940 34fd 0003 2dc96d5b 0000 0000 dbc7 0400 0000 0000 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
32 |
33 | packet 3 b88198b7aeb7 001b17000130 0800 45 00 0054 c67e 0000 79 01 ab50 08080808 0a01b5c9 0000 9140 34fd 0003 2dc9 6d5b 0000 0000 dbc7 0400 0000 0000 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
34 | expect 3 b88198b7aeb7 001b17000130 0800 45 00 0054 c67e 0000 79 01 ab50 08080808 0a01b5c9 0000 9140 34fd 0003 2dc9 6d5b 0000 0000 dbc7 0400 0000 0000 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637
--------------------------------------------------------------------------------
/tests/xdp3.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | struct Headers {
41 | Ethernet ethernet;
42 | IPv4 ipv4;
43 | }
44 |
45 | parser Parser(packet_in packet, out Headers hd) {
46 | state start {
47 | packet.extract(hd.ethernet);
48 | transition select(hd.ethernet.protocol) {
49 | 16w0x800: parse_ipv4;
50 | default: accept;
51 | }
52 | }
53 |
54 | state parse_ipv4 {
55 | packet.extract(hd.ipv4);
56 | transition accept;
57 | }
58 | }
59 |
60 | control Ingress(inout Headers hdr, in xdp_input xin, out xdp_output xout) {
61 |
62 | bool xoutdrop = false;
63 |
64 | action Fallback_action()
65 | {
66 | xoutdrop = false;
67 | }
68 |
69 | action Drop_action()
70 | {
71 | xoutdrop = true;
72 | }
73 |
74 | table dstmactable {
75 | key = { hdr.ethernet.destination : exact; }
76 | actions = {
77 | Fallback_action;
78 | Drop_action;
79 | }
80 | default_action = Drop_action;
81 | implementation = hash_table(64);
82 | }
83 |
84 | apply {
85 | dstmactable.apply();
86 | xout.output_port = 0;
87 | xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
88 | }
89 | }
90 |
91 | control Deparser(in Headers hdrs, packet_out packet) {
92 | apply {
93 | packet.emit(hdrs.ethernet);
94 | packet.emit(hdrs.ipv4);
95 | }
96 | }
97 |
98 | xdp(Parser(), Ingress(), Deparser()) main;
99 |
--------------------------------------------------------------------------------
/tests/xdp4.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | struct Headers {
41 | Ethernet ethernet;
42 | IPv4 ipv4;
43 | }
44 |
45 | parser Parser(packet_in packet, out Headers hd) {
46 | state start {
47 | packet.extract(hd.ethernet);
48 | transition select(hd.ethernet.protocol) {
49 | 16w0x800: parse_ipv4;
50 | default: accept;
51 | }
52 | }
53 |
54 | state parse_ipv4 {
55 | packet.extract(hd.ipv4);
56 | transition accept;
57 | }
58 | }
59 |
60 | control Ingress(inout Headers hdr, in xdp_input xin, out xdp_output xout) {
61 |
62 | bool xoutdrop = false;
63 |
64 | action Fallback_action()
65 | {
66 | xoutdrop = false;
67 | }
68 |
69 | action Drop_action()
70 | {
71 | xoutdrop = true;
72 | }
73 |
74 | table dstmactable {
75 | key = { hdr.ethernet.destination : exact;
76 | hdr.ethernet.protocol: exact;}
77 | actions = {
78 | Fallback_action;
79 | Drop_action;
80 | }
81 | default_action = Drop_action;
82 | implementation = hash_table(64);
83 | }
84 |
85 | apply {
86 | dstmactable.apply();
87 | xout.output_port = 0;
88 | xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
89 | }
90 | }
91 |
92 | control Deparser(in Headers hdrs, packet_out packet) {
93 | apply {
94 | packet.emit(hdrs.ethernet);
95 | packet.emit(hdrs.ipv4);
96 | }
97 | }
98 |
99 | xdp(Parser(), Ingress(), Deparser()) main;
100 |
--------------------------------------------------------------------------------
/tests/xdp5.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | struct Headers {
41 | Ethernet ethernet;
42 | IPv4 ipv4;
43 | }
44 |
45 | parser Parser(packet_in packet, out Headers hd) {
46 | state start {
47 | packet.extract(hd.ethernet);
48 | transition select(hd.ethernet.protocol) {
49 | 16w0x800: parse_ipv4;
50 | default: accept;
51 | }
52 | }
53 |
54 | state parse_ipv4 {
55 | packet.extract(hd.ipv4);
56 | transition accept;
57 | }
58 | }
59 |
60 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
61 |
62 | bool xoutdrop = false;
63 |
64 | action Fallback_action()
65 | {
66 | xoutdrop = false;
67 | }
68 |
69 | action Drop_action()
70 | {
71 | xoutdrop = true;
72 | }
73 |
74 | table dstmactable {
75 | key = { hd.ethernet.protocol : exact; }
76 | actions = {
77 | Fallback_action;
78 | Drop_action;
79 | }
80 | default_action = Drop_action;
81 | implementation = hash_table(64);
82 | }
83 |
84 | apply {
85 | dstmactable.apply();
86 | xout.output_port = 0;
87 | xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
88 | }
89 | }
90 |
91 | control Deparser(in Headers hdrs, packet_out packet) {
92 | apply {
93 | packet.emit(hdrs.ethernet);
94 | packet.emit(hdrs.ipv4);
95 | }
96 | }
97 |
98 | xdp(Parser(), Ingress(), Deparser()) main;
99 |
--------------------------------------------------------------------------------
/tests/xdp6.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | struct Headers {
41 | Ethernet ethernet;
42 | IPv4 ipv4;
43 | }
44 |
45 | struct action_md_t {
46 | bit<8> ttl;
47 | }
48 |
49 | parser Parser(packet_in packet, out Headers hd) {
50 | state start {
51 | packet.extract(hd.ethernet);
52 | transition select(hd.ethernet.protocol) {
53 | 16w0x800: parse_ipv4;
54 | default: accept;
55 | }
56 | }
57 |
58 | state parse_ipv4 {
59 | packet.extract(hd.ipv4);
60 | transition accept;
61 | }
62 | }
63 |
64 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
65 |
66 | action SetTTL_action(action_md_t md)
67 | {
68 | hd.ipv4.ttl = md.ttl;
69 | xout.output_action = xdp_action.XDP_PASS;
70 | }
71 |
72 | action Fallback_action()
73 | {
74 | xout.output_action = xdp_action.XDP_PASS;
75 | }
76 |
77 | action Drop_action()
78 | {
79 | xout.output_action = xdp_action.XDP_DROP;
80 | }
81 |
82 | table dstmactable {
83 | key = {
84 | hd.ethernet.protocol : exact;
85 | hd.ipv4.dstAddr : exact;
86 | }
87 | actions = {
88 | Fallback_action;
89 | Drop_action;
90 | SetTTL_action;
91 | }
92 | default_action = Drop_action;
93 | implementation = hash_table(64);
94 | }
95 |
96 | apply {
97 | dstmactable.apply();
98 | xout.output_port = 0;
99 | }
100 | }
101 |
102 | control Deparser(in Headers hdrs, packet_out packet) {
103 | apply {
104 | packet.emit(hdrs.ethernet);
105 | packet.emit(hdrs.ipv4);
106 | }
107 | }
108 |
109 | xdp(Parser(), Ingress(), Deparser()) main;
110 |
--------------------------------------------------------------------------------
/tests/xdp7.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> checksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | header icmp_t {
41 | bit<16> typeCode;
42 | bit<16> checksum;
43 | }
44 |
45 | header tcp_t {
46 | bit<16> srcPort;
47 | bit<16> dstPort;
48 | bit<32> seqNo;
49 | bit<32> ackNo;
50 | bit<4> dataOffset;
51 | bit<4> res;
52 | bit<8> flags;
53 | bit<16> window;
54 | bit<16> checksum;
55 | bit<16> urgentPtr;
56 | }
57 |
58 | header udp_t {
59 | bit<16> srcPort;
60 | bit<16> dstPort;
61 | bit<16> length_;
62 | bit<16> checksum;
63 | }
64 |
65 |
66 | struct Headers {
67 | Ethernet ethernet;
68 | IPv4 ipv4;
69 | tcp_t tcp;
70 | udp_t udp;
71 | icmp_t icmp;
72 | }
73 |
74 | parser Parser(packet_in packet, out Headers hd) {
75 | state start {
76 | packet.extract(hd.ethernet);
77 | transition select(hd.ethernet.protocol) {
78 | 16w0x800: parse_ipv4;
79 | default: accept;
80 | }
81 | }
82 | state parse_ipv4 {
83 | packet.extract(hd.ipv4);
84 | transition select(hd.ipv4.protocol) {
85 | 8w6: parse_tcp;
86 | 8w17: parse_udp;
87 | 8w1: parse_icmp;
88 | default: accept;
89 | }
90 | }
91 | state parse_icmp {
92 | packet.extract(hd.icmp);
93 | transition accept;
94 | }
95 | state parse_tcp {
96 | packet.extract(hd.tcp);
97 | transition accept;
98 | }
99 | state parse_udp {
100 | packet.extract(hd.udp);
101 | transition accept;
102 | }
103 | }
104 |
105 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
106 |
107 | bool xoutdrop = false;
108 | // from, to are host byte order
109 | bit<16> from;
110 | bit<16> to;
111 | bit<32> from_addr;
112 | bit<32> to_addr;
113 |
114 | action Fallback_action()
115 | {
116 | #if 0
117 | // UDP port
118 | from = hd.udp.dstPort;
119 | to = 16w0x400;
120 | hd.udp.dstPort = to;
121 | hd.udp.checksum = csum_replace2(hd.udp.checksum, from, to);
122 |
123 | // UDP IP addr
124 | from_addr = hd.ipv4.dstAddr;
125 | to_addr = 32w0x01020304;
126 | hd.ipv4.dstAddr = to_addr;
127 | hd.ipv4.checksum = csum_replace4(hd.ipv4.checksum, from_addr, to_addr);
128 | hd.udp.checksum = csum_replace4(hd.udp.checksum, from_addr, to_addr);
129 | #endif
130 | // TCP
131 | from = hd.tcp.srcPort;
132 | to = 16w0x841;
133 | hd.tcp.srcPort = to;
134 | hd.tcp.checksum = csum_replace2(hd.tcp.checksum, from, to);
135 |
136 | // TCP IP addr
137 | from_addr = hd.ipv4.srcAddr;
138 | to_addr = 32w0x05060708;
139 | hd.ipv4.srcAddr = to_addr;
140 | hd.ipv4.checksum = csum_replace4(hd.ipv4.checksum, from_addr, to_addr);
141 | hd.tcp.checksum = csum_replace4(hd.tcp.checksum, from_addr, to_addr);
142 |
143 | xoutdrop = false;
144 | }
145 |
146 | action Drop_action()
147 | {
148 | xoutdrop = true;
149 | }
150 |
151 | table dstmactable {
152 | key = { hd.ethernet.protocol : exact; }
153 | actions = {
154 | Fallback_action;
155 | Drop_action;
156 | }
157 | default_action = Fallback_action;
158 | implementation = hash_table(64);
159 | }
160 |
161 | apply {
162 | dstmactable.apply();
163 | xout.output_port = 0;
164 | xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
165 | }
166 | }
167 |
168 | control Deparser(in Headers hdrs, packet_out packet) {
169 | apply {
170 | packet.emit(hdrs.ethernet);
171 | packet.emit(hdrs.ipv4);
172 |
173 | // hit Verifier MAX_BPF_STACK issue
174 | // packet.emit(hdrs.tcp);
175 | // packet.emit(hdrs.udp);
176 |
177 | packet.emit(hdrs.icmp);
178 | packet.emit(hdrs.udp);
179 | packet.emit(hdrs.tcp);
180 | }
181 | }
182 |
183 | xdp(Parser(), Ingress(), Deparser()) main;
184 |
--------------------------------------------------------------------------------
/tests/xdp8.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | /* change ipv4.ttl to 4
20 | * update iph->csum
21 | */
22 |
23 | header Ethernet {
24 | bit<48> source;
25 | bit<48> destination;
26 | bit<16> protocol;
27 | }
28 |
29 | header IPv4 {
30 | bit<4> version;
31 | bit<4> ihl;
32 | bit<8> diffserv;
33 | bit<16> totalLen;
34 | bit<16> identification;
35 | bit<3> flags;
36 | bit<13> fragOffset;
37 | bit<8> ttl;
38 | bit<8> protocol;
39 | bit<16> hdrChecksum;
40 | bit<32> srcAddr;
41 | bit<32> dstAddr;
42 | }
43 |
44 | struct Headers {
45 | Ethernet ethernet;
46 | IPv4 ipv4;
47 | }
48 |
49 | parser Parser(packet_in packet, out Headers hd) {
50 | state start {
51 | packet.extract(hd.ethernet);
52 | transition select(hd.ethernet.protocol) {
53 | 16w0x800: parse_ipv4;
54 | default: accept;
55 | }
56 | }
57 | state parse_ipv4 {
58 | packet.extract(hd.ipv4);
59 | transition select(hd.ipv4.protocol) {
60 | default: accept;
61 | }
62 | }
63 | }
64 |
65 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
66 |
67 | bool xoutdrop = false;
68 |
69 | action SetTTL_action()
70 | {
71 | hd.ipv4.ttl = 4;
72 | xoutdrop = false;
73 | }
74 |
75 | action Fallback_action()
76 | {
77 | xoutdrop = false;
78 | }
79 |
80 | action Drop_action()
81 | {
82 | xoutdrop = true;
83 | }
84 |
85 | table dstmactable {
86 | key = { hd.ipv4.dstAddr : exact; }
87 | actions = {
88 | SetTTL_action;
89 | Fallback_action;
90 | Drop_action;
91 | }
92 | default_action = SetTTL_action;
93 | implementation = hash_table(64);
94 | }
95 |
96 | apply {
97 | dstmactable.apply();
98 | xout.output_port = 0;
99 | xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
100 | }
101 | }
102 |
103 | control Deparser(in Headers hdrs, packet_out packet) {
104 | apply {
105 | packet.emit(hdrs.ethernet);
106 | packet.emit(hdrs.ipv4);
107 | }
108 | }
109 |
110 | xdp(Parser(), Ingress(), Deparser()) main;
111 |
--------------------------------------------------------------------------------
/tests/xdp9.p4:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMWare, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdp_model.p4"
18 |
19 | header Ethernet {
20 | bit<48> destination;
21 | bit<48> source;
22 | bit<16> protocol;
23 | }
24 |
25 | header IPv4 {
26 | bit<4> version;
27 | bit<4> ihl;
28 | bit<8> diffserv;
29 | bit<16> totalLen;
30 | bit<16> identification;
31 | bit<3> flags;
32 | bit<13> fragOffset;
33 | bit<8> ttl;
34 | bit<8> protocol;
35 | bit<16> hdrChecksum;
36 | bit<32> srcAddr;
37 | bit<32> dstAddr;
38 | }
39 |
40 | header icmp_t {
41 | bit<16> typeCode;
42 | bit<16> hdrChecksum;
43 | }
44 |
45 | header tcp_t {
46 | bit<16> srcPort;
47 | bit<16> dstPort;
48 | bit<32> seqNo;
49 | bit<32> ackNo;
50 | bit<4> dataOffset;
51 | bit<4> res;
52 | bit<8> flags;
53 | bit<16> window;
54 | bit<16> checksum;
55 | bit<16> urgentPtr;
56 | }
57 |
58 | header udp_t {
59 | bit<16> srcPort;
60 | bit<16> dstPort;
61 | bit<16> length_;
62 | bit<16> checksum;
63 | }
64 |
65 |
66 | struct Headers {
67 | Ethernet ethernet;
68 | IPv4 ipv4;
69 | tcp_t tcp;
70 | udp_t udp;
71 | icmp_t icmp;
72 | }
73 |
74 | parser Parser(packet_in packet, out Headers hd) {
75 | state start {
76 | packet.extract(hd.ethernet);
77 | transition select(hd.ethernet.protocol) {
78 | 16w0x800: parse_ipv4;
79 | default: accept;
80 | }
81 | }
82 | state parse_ipv4 {
83 | packet.extract(hd.ipv4);
84 | transition select(hd.ipv4.protocol) {
85 | 8w6: parse_tcp;
86 | 8w17: parse_udp;
87 | 8w1: parse_icmp;
88 | default: accept;
89 | }
90 | }
91 | state parse_icmp {
92 | packet.extract(hd.icmp);
93 | transition accept;
94 | }
95 | state parse_tcp {
96 | packet.extract(hd.tcp);
97 | transition accept;
98 | }
99 | state parse_udp {
100 | packet.extract(hd.udp);
101 | transition accept;
102 | }
103 | }
104 |
105 | control Ingress(inout Headers hd, in xdp_input xin, out xdp_output xout) {
106 |
107 | bool xoutdrop = false;
108 |
109 | action Fallback_action()
110 | {
111 | hd.ipv4.ttl = 4;
112 | hd.ipv4.hdrChecksum = ebpf_ipv4_checksum(
113 | hd.ipv4.version, hd.ipv4.ihl, hd.ipv4.diffserv,
114 | hd.ipv4.totalLen, hd.ipv4.identification, hd.ipv4.flags,
115 | hd.ipv4.fragOffset, hd.ipv4.ttl, hd.ipv4.protocol,
116 | hd.ipv4.srcAddr, hd.ipv4.dstAddr);
117 | xoutdrop = false;
118 | }
119 |
120 | action Drop_action()
121 | {
122 | xoutdrop = true;
123 | }
124 |
125 | table dstmactable {
126 | key = { hd.ethernet.protocol : exact; }
127 | actions = {
128 | Fallback_action;
129 | Drop_action;
130 | }
131 | default_action = Fallback_action;
132 | implementation = hash_table(64);
133 | }
134 |
135 | apply {
136 | dstmactable.apply();
137 | xout.output_port = 0;
138 | xout.output_action = xoutdrop ? xdp_action.XDP_DROP : xdp_action.XDP_PASS;
139 | }
140 | }
141 |
142 | control Deparser(in Headers hdrs, packet_out packet) {
143 | apply {
144 | packet.emit(hdrs.ethernet);
145 | packet.emit(hdrs.ipv4);
146 |
147 | /* hit BPF_MAX_STACK size */
148 | // packet.emit(hdrs.tcp);
149 | // packet.emit(hdrs.udp);
150 | packet.emit(hdrs.icmp);
151 | }
152 | }
153 |
154 | xdp(Parser(), Ingress(), Deparser()) main;
155 |
--------------------------------------------------------------------------------
/tools/install_dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # exit when any command fails
4 | set -e
5 |
6 | # fetch submodules and update apt
7 | echo "Initializing submodules..."
8 | git submodule update --init --recursive
9 | sudo apt update
10 |
11 | SRC_DIR="$(pwd)"
12 |
13 | echo "Installing P4C dependencies..."
14 |
15 | # Install pip and python
16 | sudo apt install -y python3
17 | sudo apt install -y python3-pip
18 | sudo apt install -y python3-setuptools
19 |
20 | # Install the p4 compiler dependencies
21 | sudo apt install -y bison \
22 | build-essential \
23 | cmake \
24 | git \
25 | flex \
26 | libboost-dev \
27 | libboost-graph-dev \
28 | libboost-iostreams-dev \
29 | libfl-dev \
30 | libgc-dev \
31 | libgmp-dev \
32 | pkg-config
33 |
34 | # Install the eBPF dependencies
35 | sudo apt install -y libpcap-dev \
36 | libelf-dev \
37 | zlib1g-dev \
38 | llvm \
39 | clang \
40 | libprotobuf-dev \
41 | protobuf-compiler \
42 | iproute2 \
43 | tcpdump \
44 | iptables
45 |
46 | # This only works on Ubuntu 18+
47 | sudo apt install -y libprotoc-dev protobuf-compiler
48 |
49 | # install python packages using pip
50 | pip3 install --user wheel
51 | pip3 install --user pyroute2 ipaddr ply==3.8 scapy==2.4.0
52 |
53 | echo "Successfully installed P4C dependencies."
54 |
--------------------------------------------------------------------------------
/xdpBackend.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "lib/error.h"
18 | #include "lib/nullstream.h"
19 | #include "frontends/p4/evaluator/evaluator.h"
20 |
21 | #include "xdpBackend.h"
22 | #include "xdpProgram.h"
23 | #include "target.h"
24 | #include "backends/ebpf/ebpfType.h"
25 |
26 | namespace XDP {
27 |
28 | void run_xdp_backend(const EbpfOptions& options, const IR::ToplevelBlock* toplevel,
29 | P4::ReferenceMap* refMap, P4::TypeMap* typeMap) {
30 | if (toplevel == nullptr)
31 | return;
32 |
33 | auto main = toplevel->getMain();
34 | if (main == nullptr) {
35 | ::warning(ErrorType::WARN_MISSING,
36 | "Could not locate top-level block; is there a %1% module?", IR::P4Program::main);
37 | return;
38 | }
39 |
40 | EBPF::Target* target;
41 | if (options.target == "bcc") {
42 | target = new EBPF::BccTarget();
43 | } else if (options.target == "kernel") {
44 | target = new EBPF::KernelSamplesTarget();
45 | } else if (options.target.isNullOrEmpty() || options.target == "xdp") {
46 | target = new XdpTarget();
47 | } else {
48 | ::error(ErrorType::ERR_UNSUPPORTED,
49 | "Unknown target %s; legal choices are 'bcc', 'xdp', and 'kernel'", options.target);
50 | return;
51 | }
52 |
53 | EBPF::EBPFTypeFactory::createFactory(typeMap);
54 | auto prog = new XDPProgram(options, toplevel->getProgram(), refMap, typeMap, toplevel);
55 | if (!prog->build())
56 | return;
57 |
58 | if (options.outputFile.isNullOrEmpty())
59 | return;
60 | cstring cfile = options.outputFile;
61 | auto cstream = openFile(cfile, false);
62 | if (cstream == nullptr)
63 | return;
64 |
65 | cstring hfile;
66 | const char* dot = cfile.findlast('.');
67 | if (dot == nullptr)
68 | hfile = cfile + ".h";
69 | else
70 | hfile = cfile.before(dot) + ".h";
71 | auto hstream = openFile(hfile, false);
72 | if (hstream == nullptr)
73 | return;
74 |
75 | EBPF::CodeBuilder c(target);
76 | EBPF::CodeBuilder h(target);
77 | // The order is important
78 | prog->emitH(&h, hfile);
79 | prog->emitC(&c, hfile);
80 |
81 | *cstream << c.toString();
82 | *hstream << h.toString();
83 | cstream->flush();
84 | hstream->flush();
85 | }
86 |
87 | } // namespace XDP
88 |
--------------------------------------------------------------------------------
/xdpBackend.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #ifndef _EXTENSIONS_P4C_XDP_XDPBACKEND_H_
18 | #define _EXTENSIONS_P4C_XDP_XDPBACKEND_H_
19 |
20 | #include "backends/ebpf/ebpfOptions.h"
21 | #include "ir/ir.h"
22 | #include "frontends/p4/evaluator/evaluator.h"
23 |
24 | namespace XDP {
25 |
26 | void run_xdp_backend(const EbpfOptions& options, const IR::ToplevelBlock* toplevel,
27 | P4::ReferenceMap* refMap, P4::TypeMap* typeMap);
28 |
29 | } // namespace XDP
30 |
31 | #endif /* _EXTENSIONS_P4C_XDP_XDPBACKEND_H_ */
32 |
--------------------------------------------------------------------------------
/xdpControl.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdpControl.h"
18 | #include "lib/error.h"
19 | #include "backends/ebpf/ebpfControl.h"
20 |
21 | namespace XDP {
22 |
23 | XDPSwitch::XDPSwitch(const XDPProgram* program,
24 | const IR::ControlBlock* block,
25 | const IR::Parameter* parserHeaders) :
26 | EBPF::EBPFControl(program, block, parserHeaders),
27 | inputMeta(nullptr), outputMeta(nullptr) {}
28 |
29 | bool XDPSwitch::build() {
30 | hitVariable = program->refMap->newName("hit");
31 | auto pl = controlBlock->container->type->applyParams;
32 | if (pl->size() != 3) {
33 | ::error(ErrorType::ERR_EXPECTED,
34 | "Expected switch block to have exactly 3 parameters");
35 | return false;
36 | }
37 |
38 | auto it = pl->parameters.begin();
39 | headers = *it;
40 | ++it;
41 | inputMeta = *it;
42 | ++it;
43 | outputMeta = *it;
44 |
45 | codeGen = new EBPF::ControlBodyTranslator(this);
46 | codeGen->substitute(headers, parserHeaders);
47 |
48 | scanConstants();
49 | return ::errorCount() == 0;
50 | }
51 |
52 | //////////////////////////////////////////////////////////////////////////
53 |
54 | namespace {
55 |
56 | class OutHeaderSize final : public EBPF::CodeGenInspector {
57 | P4::ReferenceMap* refMap;
58 | P4::TypeMap* typeMap;
59 | const XDPProgram* program;
60 |
61 | std::map substitution;
62 |
63 | bool illegal(const IR::Statement* statement)
64 | { ::error(ErrorType::ERR_UNSUPPORTED,
65 | "%1%: not supported in deparser", statement); return false; }
66 |
67 | public:
68 | OutHeaderSize(P4::ReferenceMap* refMap, P4::TypeMap* typeMap,
69 | const XDPProgram* program):
70 | EBPF::CodeGenInspector(refMap, typeMap), refMap(refMap), typeMap(typeMap),
71 | program(program) {
72 | CHECK_NULL(refMap); CHECK_NULL(typeMap); CHECK_NULL(program);
73 | setName("OutHeaderSize"); }
74 | bool preorder(const IR::PathExpression* expression) override {
75 | auto decl = refMap->getDeclaration(expression->path, true);
76 | auto param = decl->getNode()->to();
77 | if (param != nullptr) {
78 | auto subst = ::get(substitution, param);
79 | if (subst != nullptr) {
80 | builder->append(subst->name);
81 | return false;
82 | }
83 | }
84 | builder->append(expression->path->name);
85 | return false;
86 | }
87 | bool preorder(const IR::SwitchStatement* statement) override
88 | { return illegal(statement); }
89 | bool preorder(const IR::AssignmentStatement* statement) override
90 | { return illegal(statement); }
91 | bool preorder(const IR::ReturnStatement* statement) override
92 | { return illegal(statement); }
93 | bool preorder(const IR::ExitStatement* statement) override
94 | { return illegal(statement); }
95 | bool preorder(const IR::MethodCallStatement* statement) override {
96 | auto &p4lib = P4::P4CoreLibrary::instance;
97 |
98 | auto mi = P4::MethodInstance::resolve(statement->methodCall, refMap, typeMap);
99 | auto method = mi->to();
100 | if (method == nullptr)
101 | return illegal(statement);
102 |
103 | auto declType = method->originalExternType;
104 | if (declType->name.name != p4lib.packetOut.name ||
105 | method->method->name.name != p4lib.packetOut.emit.name ||
106 | method->expr->arguments->size() != 1) {
107 | return illegal(statement);
108 | }
109 |
110 | auto h = method->expr->arguments->at(0);
111 | auto type = typeMap->getType(h);
112 | auto ht = type->to();
113 | if (ht == nullptr) {
114 | ::error(ErrorType::ERR_INVALID, "Cannot emit a non-header type %1%", h);
115 | return false;
116 | }
117 | unsigned width = ht->width_bits();
118 |
119 | builder->append("if (");
120 | visit(h);
121 | builder->append(".ebpf_valid) ");
122 | builder->appendFormat("%s += %d;", program->outHeaderLengthVar.c_str(), width);
123 | return false;
124 | }
125 |
126 | void substitute(const IR::Parameter* p, const IR::Parameter* with)
127 | { substitution.emplace(p, with); }
128 | };
129 |
130 | } // namespace
131 |
132 | XDPDeparser::XDPDeparser(const XDPProgram* program, const IR::ControlBlock* block,
133 | const IR::Parameter* parserHeaders) :
134 | EBPF::EBPFControl(program, block, parserHeaders), packet(nullptr) {}
135 |
136 | bool XDPDeparser::build() {
137 | hitVariable = program->refMap->newName("hit");
138 | auto pl = controlBlock->container->type->applyParams;
139 | if (pl->size() != 2) {
140 | ::error(ErrorType::ERR_EXPECTED, "Expected switch block to have exactly 3 parameters");
141 | return false;
142 | }
143 |
144 | auto it = pl->parameters.begin();
145 | headers = *it;
146 | ++it;
147 | packet = *it;
148 |
149 | codeGen = new EBPF::ControlBodyTranslator(this);
150 | codeGen->substitute(headers, parserHeaders);
151 |
152 | return true;
153 | }
154 |
155 | void XDPDeparser::emit(EBPF::CodeBuilder* builder) {
156 | OutHeaderSize ohs(program->refMap, program->typeMap,
157 | static_cast(program));
158 | ohs.substitute(headers, parserHeaders);
159 | ohs.setBuilder(builder);
160 |
161 | builder->emitIndent();
162 | (void)controlBlock->container->body->apply(ohs);
163 | builder->newline();
164 |
165 | builder->emitIndent();
166 | builder->appendFormat("bpf_xdp_adjust_head(%s, BYTES(%s) - BYTES(%s));",
167 | program->model.CPacketName.str(),
168 | program->offsetVar.c_str(),
169 | getProgram()->outHeaderLengthVar.c_str());
170 | builder->newline();
171 |
172 | builder->emitIndent();
173 | builder->appendFormat("%s = %s;",
174 | program->packetStartVar,
175 | builder->target->dataOffset(program->model.CPacketName.str()));
176 | builder->newline();
177 | builder->emitIndent();
178 | builder->appendFormat("%s = %s;",
179 | program->packetEndVar,
180 | builder->target->dataEnd(program->model.CPacketName.str()));
181 | builder->newline();
182 |
183 | builder->emitIndent();
184 | builder->appendFormat("%s = 0;", program->offsetVar.c_str());
185 | builder->newline();
186 |
187 | EBPF::EBPFControl::emit(builder);
188 | }
189 |
190 | } // namespace XDP
191 |
--------------------------------------------------------------------------------
/xdpControl.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2013-present Barefoot Networks, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #ifndef _EXTENSIONS_P4C_XDP_XDPCONTROL_H_
18 | #define _EXTENSIONS_P4C_XDP_XDPCONTROL_H_
19 |
20 | #include "backends/ebpf/ebpfControl.h"
21 | #include "xdpProgram.h"
22 |
23 | namespace XDP {
24 |
25 | class XDPSwitch : public EBPF::EBPFControl {
26 | public:
27 | const IR::Parameter* inputMeta;
28 | const IR::Parameter* outputMeta;
29 |
30 | XDPSwitch(const XDPProgram* program, const IR::ControlBlock* block,
31 | const IR::Parameter* parserHeaders);
32 | bool build() override;
33 | };
34 |
35 | class XDPDeparser : public EBPF::EBPFControl {
36 | public:
37 | const IR::Parameter* packet;
38 |
39 | XDPDeparser(const XDPProgram* program, const IR::ControlBlock* block,
40 | const IR::Parameter* parserHeaders);
41 | bool build() override;
42 | void emit(EBPF::CodeBuilder* builder) override;
43 | const XDPProgram* getProgram() const
44 | { return dynamic_cast(program); }
45 | };
46 |
47 | } // namespace XDP
48 |
49 | #endif /* _EXTENSIONS_P4C_XDP_XDPCONTROL_H_ */
50 |
--------------------------------------------------------------------------------
/xdpModel.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "xdpModel.h"
18 |
19 | namespace XDP {
20 |
21 | XDPModel XDPModel::instance;
22 |
23 | } // namespace XDP
24 |
--------------------------------------------------------------------------------
/xdpModel.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 VMware, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #ifndef _XDPMODEL_H_
18 | #define _XDPMODEL_H_
19 |
20 | #include "backends/ebpf/ebpfModel.h"
21 |
22 | namespace XDP {
23 |
24 | struct XDP_Action_Model : public ::Model::Enum_Model {
25 | XDP_Action_Model() : Enum_Model("xdp_action"),
26 | aborted("XDP_ABORTED"), drop("XDP_DROP"),
27 | pass("XDP_PASS"), tx("XDP_TX") {}
28 | ::Model::Elem aborted;
29 | ::Model::Elem drop;
30 | ::Model::Elem pass;
31 | ::Model::Elem tx;
32 | };
33 |
34 | struct XDP_Switch_Model : public ::Model::Elem {
35 | XDP_Switch_Model() : Elem("xdp"),
36 | parser("p"), swtch("s"), deparser("d") {}
37 | ::Model::Elem parser;
38 | ::Model::Elem swtch;
39 | ::Model::Elem deparser;
40 | };
41 |
42 | struct InputMetadataModel : public ::Model::Type_Model {
43 | InputMetadataModel() : ::Model::Type_Model("xdp_input"),
44 | inputPort("input_port"), inputPortType(IR::Type_Bits::get(32))
45 | {}
46 |
47 | ::Model::Elem inputPort;
48 | const IR::Type* inputPortType;
49 | };
50 |
51 | struct OutputMetadataModel : public ::Model::Type_Model {
52 | OutputMetadataModel() : ::Model::Type_Model("xdp_output"),
53 | outputPort("output_port"), outputPortType(IR::Type_Bits::get(32)),
54 | output_action("output_action")
55 | {}
56 |
57 | ::Model::Elem outputPort;
58 | const IR::Type* outputPortType;
59 | ::Model::Elem output_action;
60 | };
61 |
62 | // Keep this in sync with xdp_model.p4
63 | class XDPModel : public EBPF::EBPFModel {
64 | protected:
65 | XDPModel() : EBPF::EBPFModel(), xdp(), inputMetadataModel(), outputMetadataModel(),
66 | ipv4_checksum("ebpf_ipv4_checksum"),
67 | csum_replace2("csum_replace2"),
68 | csum_replace4("csum_replace4"),
69 | bpf_event_output("bpf_event_output"),
70 | bpf_ktime_get_ns("bpf_ktime_get_ns"),
71 | action_enum()
72 | {}
73 |
74 | public:
75 | static XDPModel instance;
76 | XDP_Switch_Model xdp;
77 | InputMetadataModel inputMetadataModel;
78 | OutputMetadataModel outputMetadataModel;
79 | ::Model::Extern_Model ipv4_checksum;
80 | ::Model::Extern_Model csum_replace2;
81 | ::Model::Extern_Model csum_replace4;
82 | ::Model::Extern_Model bpf_event_output;
83 | ::Model::Extern_Model bpf_ktime_get_ns;
84 | XDP_Action_Model action_enum;
85 | };
86 |
87 | } // namespace XDP
88 |
89 | #endif /* _XDPMODEL_H_ */
90 |
--------------------------------------------------------------------------------
/xdpProgram.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2013-present Barefoot Networks, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #include "backends/ebpf/ebpfType.h"
18 | #include "backends/ebpf/ebpfControl.h"
19 | #include "backends/ebpf/ebpfParser.h"
20 | #include "backends/ebpf/ebpfTable.h"
21 | #include "frontends/p4/coreLibrary.h"
22 | #include "xdpProgram.h"
23 | #include "xdpControl.h"
24 |
25 | namespace XDP {
26 |
27 | bool XDPProgram::build() {
28 | auto pack = toplevel->getMain();
29 | unsigned paramCount = pack->getConstructorParameters()->size();
30 |
31 | cstring parserParamName;
32 | if (paramCount == 2) {
33 | parserParamName = model.filter.parser.name;
34 | } else if (paramCount == 3) {
35 | parserParamName = xdp_model.xdp.parser.name;
36 | } else {
37 | ::error(ErrorType::ERR_EXPECTED,
38 | "%1%: Expected 2 or 3 package parameters", pack);
39 | }
40 |
41 | auto pb = pack->getParameterValue(parserParamName)
42 | ->to();
43 | BUG_CHECK(pb != nullptr, "No parser block found");
44 | parser = new EBPF::EBPFParser(this, pb, typeMap);
45 | bool success = parser->build();
46 | if (!success)
47 | return success;
48 |
49 | if (paramCount == 2) {
50 | cstring controlParamName = model.filter.filter.name;
51 | auto cb = pack->getParameterValue(controlParamName)
52 | ->to();
53 | BUG_CHECK(cb != nullptr, "No control block found");
54 | control = new EBPF::EBPFControl(this, cb, parser->headers);
55 | success = control->build();
56 | if (!success)
57 | return success;
58 | } else {
59 | cstring controlParamName = xdp_model.xdp.swtch.name;
60 | auto cb = pack->getParameterValue(controlParamName)
61 | ->to();
62 | BUG_CHECK(cb != nullptr, "No control block found");
63 | control = new XDPSwitch(this, cb, parser->headers);
64 | success = control->build();
65 | if (!success)
66 | return success;
67 | }
68 |
69 | if (paramCount == 3) {
70 | auto db = pack->getParameterValue(xdp_model.xdp.deparser.name)
71 | ->to();
72 | BUG_CHECK(db != nullptr, "No deparser block found");
73 | deparser = new XDPDeparser(this, db, parser->headers);
74 | success = deparser->build();
75 | if (!success)
76 | return success;
77 | }
78 |
79 | return true;
80 | }
81 |
82 | void XDPProgram::emitTypes(EBPF::CodeBuilder* builder) {
83 | for (auto d : program->objects) {
84 | if (!d->is()) continue;
85 |
86 | if (d->is() || d->is() ||
87 | d->is() || d->is() ||
88 | d->is() || d->is())
89 | continue;
90 |
91 | if (d->is()) {
92 | if (d->to()->name == XDPModel::instance.action_enum.name)
93 | continue;
94 | }
95 |
96 | auto type = EBPF::EBPFTypeFactory::instance->create(d->to());
97 | if (type == nullptr)
98 | continue;
99 | type->emit(builder);
100 | builder->newline();
101 | }
102 | }
103 |
104 | void XDPProgram::emitC(EBPF::CodeBuilder* builder, cstring headerFile) {
105 | emitGeneratedComment(builder);
106 |
107 | if (!switchTarget()) {
108 | EBPF::EBPFProgram::emitC(builder, headerFile);
109 | return;
110 | }
111 |
112 | if (builder->target->name != "XDP") {
113 | ::error(ErrorType::ERR_EXPECTED,
114 | "This program must be compiled with --target xdp");
115 | return;
116 | }
117 |
118 | builder->appendFormat("#include \"%s\"", headerFile);
119 | builder->newline();
120 | builder->target->emitIncludes(builder);
121 | emitPreamble(builder);
122 | control->emitTableInstances(builder);
123 |
124 | builder->appendLine(
125 | "inline u16 ebpf_ipv4_checksum(u8 version, u8 ihl, u8 diffserv,\n"
126 | " u16 totalLen, u16 identification, u8 flags,\n"
127 | " u16 fragOffset, u8 ttl, u8 protocol,\n"
128 | " u32 srcAddr, u32 dstAddr) {\n"
129 | " u32 checksum = __bpf_htons(((u16)version << 12) | ((u16)ihl << 8) | (u16)diffserv);\n"
130 | " checksum += __bpf_htons(totalLen);\n"
131 | " checksum += __bpf_htons(identification);\n"
132 | " checksum += __bpf_htons(((u16)flags << 13) | fragOffset);\n"
133 | " checksum += __bpf_htons(((u16)ttl << 8) | (u16)protocol);\n"
134 | " srcAddr = __bpf_ntohl(srcAddr);\n"
135 | " dstAddr = __bpf_ntohl(dstAddr);\n"
136 | " checksum += (srcAddr >> 16) + (u16)srcAddr;\n"
137 | " checksum += (dstAddr >> 16) + (u16)dstAddr;\n"
138 | " // Fields in 'struct Headers' are host byte order.\n"
139 | " // Deparser converts to network byte-order\n"
140 | " return bpf_ntohs(~((checksum & 0xFFFF) + (checksum >> 16)));\n"
141 | "}");
142 |
143 | builder->appendLine(
144 | "inline u16 csum16_add(u16 csum, u16 addend) {\n"
145 | " u16 res = csum;\n"
146 | " res += addend;\n"
147 | " return (res + (res < addend));\n"
148 | "}\n"
149 | "inline u16 csum16_sub(u16 csum, u16 addend) {\n"
150 | " return csum16_add(csum, ~addend);\n"
151 | "}\n"
152 | "inline u16 csum_replace2(u16 csum, u16 old, u16 new) {\n"
153 | " return (~csum16_add(csum16_sub(~csum, old), new));\n"
154 | "}\n");
155 |
156 | builder->appendLine(
157 | "inline u16 csum_fold(u32 csum) {\n"
158 | " u32 r = csum << 16 | csum >> 16;\n"
159 | " csum = ~csum;\n"
160 | " csum -= r;\n"
161 | " return (u16)(csum >> 16);\n"
162 | "}\n"
163 | "inline u32 csum_unfold(u16 csum) {\n"
164 | " return (u32)csum;\n"
165 | "}\n"
166 | "inline u32 csum32_add(u32 csum, u32 addend) {\n"
167 | " u32 res = csum;\n"
168 | " res += addend;\n"
169 | " return (res + (res < addend));\n"
170 | "}\n"
171 | "inline u32 csum32_sub(u32 csum, u32 addend) {\n"
172 | " return csum32_add(csum, ~addend);\n"
173 | "}\n"
174 | "inline u16 csum_replace4(u16 csum, u32 from, u32 to) {\n"
175 | " u32 tmp = csum32_sub(~csum_unfold(csum), from);\n"
176 | " return csum_fold(csum32_add(tmp, to));\n"
177 | "}\n");
178 |
179 | builder->appendLine(
180 | "struct bpf_elf_map SEC(\"maps\") perf_event = {\n"
181 | " .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,\n"
182 | " .size_key = sizeof(u32),\n"
183 | " .size_value = sizeof(u32),\n"
184 | " .pinning = 1,\n"
185 | " .max_elem = 2,\n"
186 | "};\n"
187 | "#define BPF_PERF_EVENT_OUTPUT() do {\\\n"
188 | " int pktsize = (int)(skb->data_end - skb->data);\\\n"
189 | " bpf_perf_event_output(skb, &perf_event, ((u64)pktsize << 32), &pktsize, 4);\\\n"
190 | "} while(0);\n");
191 |
192 | builder->appendLine(
193 | "#define BPF_KTIME_GET_NS() ({\\\n"
194 | " u32 ___ts = (u32)bpf_ktime_get_ns(); ___ts; })\\\n");
195 |
196 | // The table used for forwarding: we write the output in it
197 | // TODO: this should use target->emitTableDecl().
198 | // We can't do it today because it has a different map type PERCPU_ARRAY
199 | builder->emitIndent();
200 | builder->appendFormat("struct bpf_elf_map SEC(\"maps\") %s = ", outTableName.c_str());
201 | builder->blockStart();
202 | builder->emitIndent();
203 | builder->append(".type = ");
204 | builder->appendLine("BPF_MAP_TYPE_PERCPU_ARRAY,");
205 |
206 | builder->emitIndent();
207 | builder->append(".size_key = sizeof(u32),");
208 | builder->newline();
209 |
210 | builder->emitIndent();
211 | builder->appendFormat(".size_value = sizeof(u32),");
212 | builder->newline();
213 |
214 | builder->emitIndent();
215 | builder->appendFormat(".pinning = 2, /* PIN_OBJECT_NS */");
216 | builder->newline();
217 |
218 | builder->emitIndent();
219 | builder->appendFormat(".max_elem = 1 /* No multicast support */");
220 | builder->newline();
221 |
222 | builder->blockEnd(false);
223 | builder->endOfStatement(true);
224 |
225 | builder->newline();
226 | builder->emitIndent();
227 | builder->target->emitCodeSection(builder, "prog");
228 | builder->emitIndent();
229 | builder->target->emitMain(builder, functionName, model.CPacketName.str());
230 | builder->blockStart();
231 |
232 | emitHeaderInstances(builder);
233 | builder->append(" = ");
234 | parser->headerType->emitInitializer(builder);
235 | builder->endOfStatement(true);
236 |
237 | emitLocalVariables(builder);
238 | builder->newline();
239 | builder->emitIndent();
240 | builder->appendFormat("goto %s;", IR::ParserState::start.c_str());
241 | builder->newline();
242 |
243 | parser->emit(builder);
244 | emitPipeline(builder);
245 |
246 | builder->emitIndent();
247 | builder->append(endLabel);
248 | builder->appendLine(":");
249 |
250 | // write output port to a table
251 | builder->emitIndent();
252 | builder->appendFormat("bpf_map_update_elem(&%s, &%s, &%s.%s, BPF_ANY)",
253 | outTableName.c_str(), zeroKey.c_str(),
254 | getSwitch()->outputMeta->name.name,
255 | XDPModel::instance.outputMetadataModel.outputPort.str());
256 | builder->endOfStatement(true);
257 |
258 | builder->emitIndent();
259 | builder->appendFormat("return %s.%s",
260 | getSwitch()->outputMeta->name.name,
261 | XDPModel::instance.outputMetadataModel.output_action.str());
262 | builder->endOfStatement(true);
263 | builder->blockEnd(true); // end of function
264 |
265 | builder->target->emitLicense(builder, license);
266 | }
267 |
268 | void XDPProgram::emitPipeline(EBPF::CodeBuilder* builder) {
269 | builder->emitIndent();
270 | builder->append(IR::ParserState::accept);
271 | builder->append(":");
272 | builder->newline();
273 |
274 | builder->emitIndent();
275 | builder->blockStart();
276 | control->emit(builder);
277 | builder->blockEnd(true);
278 |
279 | if (switchTarget()) {
280 | builder->emitIndent();
281 | builder->append("/* deparser */");
282 | builder->newline();
283 | builder->emitIndent();
284 | builder->blockStart();
285 | deparser->emit(builder);
286 | builder->blockEnd(true);
287 | }
288 | }
289 |
290 | void XDPProgram::emitLocalVariables(EBPF::CodeBuilder* builder) {
291 | if (!switchTarget()) {
292 | EBPF::EBPFProgram::emitLocalVariables(builder);
293 | return;
294 | }
295 |
296 | builder->emitIndent();
297 | builder->appendFormat("unsigned %s = 0;", offsetVar);
298 | builder->newline();
299 |
300 | builder->emitIndent();
301 | builder->appendFormat("enum %s %s = %s;", errorEnum, errorVar,
302 | P4::P4CoreLibrary::instance.noError.str());
303 | builder->newline();
304 |
305 | builder->emitIndent();
306 | builder->appendFormat("void* %s = %s;",
307 | packetStartVar, builder->target->dataOffset(model.CPacketName.str()));
308 | builder->newline();
309 | builder->emitIndent();
310 | builder->appendFormat("void* %s = %s;",
311 | packetEndVar, builder->target->dataEnd(model.CPacketName.str()));
312 | builder->newline();
313 |
314 | builder->emitIndent();
315 | builder->appendFormat("u32 %s = 0;", zeroKey);
316 | builder->newline();
317 |
318 | builder->emitIndent();
319 | builder->appendFormat("u8 %s = 0;", byteVar);
320 | builder->newline();
321 |
322 | builder->emitIndent();
323 | builder->appendFormat("u32 %s = 0;", outHeaderLengthVar);
324 | builder->newline();
325 |
326 | builder->emitIndent();
327 | builder->appendFormat("struct %s %s;", xdp_model.outputMetadataModel.name,
328 | getSwitch()->outputMeta->name.name);
329 | builder->newline();
330 |
331 | builder->emitIndent();
332 | builder->appendFormat("/* TODO: this should be initialized by the environment. HOW? */");
333 | builder->newline();
334 |
335 | builder->emitIndent();
336 | builder->appendFormat("struct %s %s;", xdp_model.inputMetadataModel.name,
337 | getSwitch()->inputMeta->name.name);
338 | builder->newline();
339 | }
340 |
341 | XDPSwitch* XDPProgram::getSwitch() const {
342 | return dynamic_cast(control);
343 | }
344 |
345 | } // namespace XDP
346 |
--------------------------------------------------------------------------------
/xdpProgram.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2013-present Barefoot Networks, Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | #ifndef _EXTENSIONS_P4C_XDP_XDPPROGRAM_H_
18 | #define _EXTENSIONS_P4C_XDP_XDPPROGRAM_H_
19 |
20 | #include "target.h"
21 | #include "xdpModel.h"
22 | #include "ir/ir.h"
23 | #include "frontends/p4/typeMap.h"
24 | #include "frontends/p4/evaluator/evaluator.h"
25 | #include "backends/ebpf/ebpfObject.h"
26 | #include "backends/ebpf/ebpfOptions.h"
27 | #include "backends/ebpf/ebpfProgram.h"
28 |
29 | namespace XDP {
30 |
31 | class XDPDeparser;
32 | class XDPSwitch;
33 |
34 | class XDPProgram : public EBPF::EBPFProgram {
35 | public:
36 | // If the deparser is missing we are still
37 | // compiling for the old EBPF model.
38 | XDPDeparser* deparser;
39 | XDPModel& xdp_model;
40 | cstring outHeaderLengthVar;
41 | cstring outTableName;
42 |
43 | XDPProgram(const EbpfOptions& options, const IR::P4Program* program,
44 | P4::ReferenceMap* refMap, P4::TypeMap* typeMap,
45 | const IR::ToplevelBlock* toplevel) :
46 | EBPF::EBPFProgram(options, program, refMap, typeMap, toplevel),
47 | deparser(nullptr), xdp_model(XDPModel::instance) {
48 | outHeaderLengthVar = EBPF::EBPFModel::reserved("outHeaderLength");
49 | outTableName = EBPF::EBPFModel::reserved("outTable");
50 | }
51 |
52 | // If the deparser is null we are compiling for the old EBPF model
53 | bool switchTarget() const { return deparser != nullptr; }
54 |
55 | void emitC(EBPF::CodeBuilder* builder, cstring headerFile) override;
56 | bool build() override; // return 'true' on success
57 | void emitLocalVariables(EBPF::CodeBuilder* builder) override;
58 | void emitPipeline(EBPF::CodeBuilder* builder) override;
59 | XDPSwitch* getSwitch() const;
60 | void emitTypes(EBPF::CodeBuilder* builder) override;
61 | };
62 |
63 | } // namespace XDP
64 |
65 | #endif /* _EXTENSIONS_P4C_XDP_XDPPROGRAM_H_ */
66 |
--------------------------------------------------------------------------------
/xdp_target.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright 2018 VMware, Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | import sys
17 | # path to the tools folder of the compiler
18 | sys.path.insert(0, 'p4c/tools')
19 | # path to the framework repository of the compiler
20 | sys.path.insert(0, 'p4c/backends/ebpf/targets')
21 | from .kernel_target import Target as EBPFKernelTarget
22 | from testutils import *
23 |
24 |
25 | class Target(EBPFKernelTarget):
26 | EBPF_MAP_PATH = "/sys/fs/bpf/xdp/globals"
27 |
28 | def __init__(self, tmpdir, options, template, outputs):
29 | EBPFKernelTarget.__init__(self, tmpdir, options, template, outputs)
30 | # We use a different compiler, override the inherited default
31 | components = options.compiler.split("/")[0:-1]
32 | self.compiler = "/".join(components) + "/p4c-xdp"
33 | print("Compiler is", self.compiler)
34 |
35 | def compile_dataplane(self):
36 | # Just call into the parent with the target set to kernel
37 | old_target = self.options.target
38 | self.options.target = "kernel"
39 | result = super(Target, self).compile_dataplane()
40 | self.options.target = old_target
41 | return result
42 |
43 | def _create_runtime(self):
44 | # Just call into the parent with the target set to kernel
45 | old_target = self.options.target
46 | self.options.target = "kernel"
47 | result = super(Target, self)._create_runtime()
48 | self.options.target = old_target
49 | return result
50 |
51 | def _load_filter(self, bridge, proc, port_name):
52 | # Load the specified eBPF object to "port_name" ingress and egress
53 | # As a side-effect, this may create maps in /sys/fs/bpf/
54 | cmd = ("ip link set dev %s xdp obj %s verb" %
55 | (port_name, self.template + ".o"))
56 | return bridge.ns_proc_write(proc, cmd)
57 |
58 | def _attach_filters(self, bridge, proc):
59 | # Get the command to load XDP code to all the attached ports
60 | # We load XDP directly to the bridge ports instead of the edges as with tc
61 | if len(bridge.br_ports) > 0:
62 | for port in bridge.br_ports:
63 | result = self._load_filter(bridge, proc, port)
64 | bridge.ns_proc_append(proc, "")
65 | else:
66 | # No ports attached (no pcap files), load to bridge instead
67 | result = self._load_filter(bridge, proc, bridge.br_name)
68 | bridge.ns_proc_append(proc, "")
69 | if result != SUCCESS:
70 | return result
71 | return SUCCESS
72 |
--------------------------------------------------------------------------------