├── README.md ├── ubpf ├── LICENSE-APACHE ├── readelf.py ├── requirements.txt └── src │ ├── Makefile │ ├── cJSON.c │ ├── cJSON.h │ ├── cJSON.o │ ├── ebpf.h │ ├── flow_cache.c │ ├── flow_cache.h │ ├── hXDP_sim │ ├── hXDP_sim.c │ ├── hXDP_sim.o │ ├── helper_functions.c │ ├── helper_functions.h │ ├── helper_functions.o │ ├── inc │ ├── hmap.h │ ├── sclog4c.h │ ├── ubpf.h │ └── utils.h │ ├── libubpf.a │ ├── lookup3.c │ ├── lookup3.h │ ├── lookup3.o │ ├── match_unit.c │ ├── match_unit.h │ ├── match_unit.o │ ├── sclog4c.c │ ├── sclog4c.o │ ├── ubpf_array.c │ ├── ubpf_array.o │ ├── ubpf_hashmap.c │ ├── ubpf_hashmap.h │ ├── ubpf_hashmap.o │ ├── ubpf_int.h │ ├── ubpf_loader.c │ ├── ubpf_lpm.c │ ├── ubpf_lpm.h │ ├── ubpf_lpm.o │ ├── ubpf_vm.c │ ├── ubpf_vm.o │ └── uthash.h ├── use_cases ├── katran │ ├── .gen │ │ ├── katran.bin │ │ ├── katran_maps.json │ │ └── katran_mat.json │ ├── katran.bin │ ├── katran.o │ ├── katran.pcap │ ├── katran_map_entries.json │ └── katran_maps.json ├── l2_acl │ ├── .gen │ │ ├── l2acl.bin │ │ ├── l2acl_maps.json │ │ ├── l2acl_mat.json │ │ └── match_action_table_readable.txt │ ├── l2acl.o │ ├── l2acl.pcap │ ├── l2acl_map_entries.json │ └── src │ │ ├── Makefile │ │ ├── l2acl.c │ │ └── l2acl_user.c ├── nat │ ├── .gen │ │ ├── nat.bin │ │ ├── nat_maps.json │ │ ├── nat_mat.json │ │ ├── nat_readable_mat.txt │ │ └── nat_x2.pcap │ ├── nat.o │ ├── nat.pcap │ ├── nat_map_entries.json │ └── src │ │ ├── Makefile │ │ ├── dnat.c │ │ ├── dnat_user.c │ │ ├── nat_consts.h │ │ ├── nat_helpers.h │ │ ├── nat_maps.h │ │ ├── nat_pckt_parsing.h │ │ └── nat_structs.h ├── suricata │ ├── .gen │ │ ├── match_action_table_readable.txt │ │ ├── suricata.bin │ │ ├── suricata_maps.json │ │ └── suricata_mat.json │ ├── suricata.o │ ├── suricata.pcap │ └── suricata_map_entries.json ├── xdp_router │ ├── .gen │ │ ├── match_action_table_readable.txt │ │ ├── router.bin │ │ ├── router_maps.json │ │ ├── router_mat.json │ │ └── router_x2.pcap │ ├── router.o │ ├── router.pcap │ └── router_map_entries.json └── xdp_tunnel │ ├── .gen │ ├── tun.bin │ ├── tun_maps.json │ ├── tun_mat.json │ ├── tun_readable_mat.txt │ └── tun_x2.pcap │ ├── tun.o │ ├── tun.pcap │ └── tun_map_entries.json └── warp_compiler.sh /README.md: -------------------------------------------------------------------------------- 1 | # Faster Software Packet Processing on FPGA NICs with eBPF Program Warping 2 | 3 | ## Artifacts evaluation instructions 4 | 5 | ## Repository structure 6 | 7 | The repository is structured as follows: 8 | - *ubpf/* contains the eBPF/hXDP emulator software written in C, along with some utilities to generate the eBPF maps configuration and the program encoding 9 | - *use_cases/* comprises all the files needed to execute the use cases described in the paper. Moreover, inside each use case directory, there is a *.gen/* directory which contains all the files ready to get the use case running in the simulator 10 | - *warp_compiler.sh* is a script to connect to the remote instance of the Warp compiler 11 | 12 | ## Workflow 13 | 14 | This section describes the workflow from an eBPF program written in C to the execution with the uBPF emulator. 15 | 16 | 1. Compile the original program with the standard Linux eBPF LLVM compiler. For convenience, we provide an already compiled *.o* object of the program for each use case 17 | 2. The *.o* object is provided to the hXDP Warp Compiler, obtaining the match-action table configuration encoded in JSON format 18 | 3. To execute the program in the simulator, we must apply some preprocessing to the *.o* eBPF program: (i) to extract the MAP information contained in the ELF file and export it in JSON format; (ii) to output the instructions contained in the ELF in a format readable by the uBPF emulator. There is a python script that performs these tasks 19 | 4. We can now run the *vanilla* eBPF program, i.e., without the warp engine. The emulator takes as input the files described before (maps description and program) and the pcap trace, specifically constructed to trigger all the processing branches. The program outputs the execution information like the number of instructions executed and the pcap traces containing the processed packets 20 | 5. At last, we run the same eBPF program with the Warp Engine turned on, i.e., with the match-action table and the context restoration functions. The emulator takes the same inputs as in 4, plus the match-action table JSON file obtained from point 2. The program outputs the same execution information and the entry number matched in the match-action table. 21 | 22 | 23 | We can obtain the speedup in terms of the number of executed instructions by comparing the emulator outputs of the vanilla and "warped" executions. 24 | 25 | ## 1. Compile an eBPF program 26 | 27 | Different use cases compile differently: there are custom use cases implemented from the [xdp-tutorial](https://github.com/xdp-project/xdp-tutorial) repository (L2 ACL and DNAT), use-cases taken from the Linux kernel (Router and Tunnel), and two open-source projects (Katran and Suricata). We provide (and suggest using) the already LLVM compiled program for each use case since compiling the use cases can be time-consuming given the requirements and compatibility issues between OS versions. 28 | ### L2 ACL and DNAT 29 | Clone the [xdp-tutorial](https://github.com/xdp-project/xdp-tutorial). Copy the two folders' l2acl' and 'dnat' inside the xdp-tutorial folder. Now follow the xdp-tutorial repository README to compile the use-cases. 30 | 31 | ### Linux Kernel BPF examples 32 | The two use-cases can be found in the Linux kernel source tree (for the paper, we used the 5.4 kernel version): the router in samples/bpf/xdp_router_ipv4_kern.c, and the tunnel in samples/bpf/xdp_tx_iptunnel_kern.c. For the compilation of these use-cases, follow the official Linux kernel documentation. 33 | 34 | ### Katran and Suricata 35 | The [Katran](https://github.com/facebookincubator/katran) and [Suricata](https://github.com/OISF/suricata) use cases can be compiled following the instructions of their original repositories. Although, we suggest using the already compiled object contained in the *use_cases* folder. 36 | 37 | ## 2. Warp Compile to obtain the MAT 38 | 39 | The warp compiler is deployed as a service reachable at xxxx:3200. By sending the LLVM compiled .o file and the program main section name, it responds with the MAT and context restorator configuration of the program. The compiler can be reached with the script 'compile.sh': 40 | 41 | $ sudo chmod +x warp_compiler.sh 42 | $ ./warp_compiler.sh 43 | 44 | The MAT and context restorator configuration are saved in _MAT.json. 45 | 46 | | Use-case | Object file name | Section name | 47 | |----------|------------------|--------------| 48 | | L2ACL | l2acl.o | xdp | 49 | | Router | xdp_router_ipv4_kern.o | xdp_router_ipv4 | 50 | | Tunnel | xdp_tx_iptunnel_kern.o | xdp_tx_iptunnel | 51 | | DNAT | dnat.o | xdp | 52 | | Suricata | xdp_filter.o | xdp | 53 | | Katran | balancer_kern.o | xdp-balancer | 54 | 55 | 56 | ## 3. eBPF program preprocessing 57 | 58 | ### Build the simulator 59 | 60 | #### Requirements 61 | In the *ubpf/* folder, issue the following commands: 62 | 63 | $ sudo apt-get update 64 | $ sudo apt-get -y install python3 python3-pip libpcap-dev 65 | $ pip3 install -r requirements.txt 66 | 67 | #### Build 68 | 69 | To build the simulator is sufficient to issue the following command from within the ubpf directory: 70 | 71 | $ make -C src 72 | 73 | It produces an executable in the *src/* folder called __"hXDP_sim"__. 74 | 75 | ### Generate the files needed by the simulator 76 | 77 | The script responsible for the preprocessing of eBPF maps and programs is *"readelf.py"* contained in the *ubpf* directory. It produces two files: 78 | 79 | - a *"usecase.bin"* file, which contains the hexadecimal representation of the program instructions 80 | - a *"usecase_maps.json"* file, which contains a JSON representation of the maps employed in the program 81 | 82 | Execute the python script with these parameters: 83 | 84 | $ python3 readelf.py 85 | 86 | - *filename.o* is the ELF object containing the LLVM compiled program 87 | - *usecase-name* is the name used for the output files (*usecase.bin* and *usecase_maps.json*, written in the working directory) 88 | - *secname* is the section name used in the XDP program (usually *xdp*, which can be found in the main function of the C source code of the use case) 89 | 90 | ## 4. Execute the *vanilla* use case 91 | 92 | To execute a program in the simulator without the match-action table, the basic command is the following: 93 | 94 | $ ./hXDP_sim --maps usecase_maps.json --pcap usecase.pcap -e usecase_map_entries.json -l 1 usecase.bin 95 | 96 | - *usecase_maps.json* and *usecase.bin* are the files generated by the *readelf.py* script 97 | - *usecase.pcap* is the pcap trace that provides the packets for the specific use case 98 | - *usecase_map_entries.json* is needed to populate the map entries 99 | - *-l 1* sets the log level. 1 for basic information, 3 for extended logs (prints the context for each instruction) 100 | 101 | As an example, we can run the *l2 acl* use case as follows: 102 | 103 | $ ./vm/hXDP_sim --maps use_cases/l2_acl/l2acl_maps.json --pcap use_cases/l2_acl/l2acl.pcap -e use_cases/l2_acl/l2acl_map_entries.json -l 1 use_cases/l2_acl/l2acl.bin 104 | 105 | 106 | which produces this output: 107 | 108 | hXDP_sim.c:514: info: In function main: Packet #1 109 | ubpf_vm.c:783: info: In function ubpf_exec: Instructions count: 15 110 | hXDP_sim.c:567: info: In function main: return 0x1 111 | 112 | hXDP_sim.c:514: info: In function main: Packet #2 113 | ubpf_vm.c:783: info: In function ubpf_exec: Instructions count: 40 114 | hXDP_sim.c:567: info: In function main: return 0x2 115 | 116 | hXDP_sim.c:514: info: In function main: Packet #3 117 | ubpf_vm.c:783: info: In function ubpf_exec: Instructions count: 17 118 | hXDP_sim.c:567: info: In function main: return 0x2 119 | 120 | hXDP_sim.c:514: info: In function main: Packet #4 121 | ubpf_vm.c:783: info: In function ubpf_exec: Instructions count: 39 122 | hXDP_sim.c:567: info: In function main: return 0x1 123 | 124 | This log displays the number of the processed packet, the number of instructions executed, and the return code of the XDP program (i.e., XDP_ABORTED=0, XDP_DROP=1, XDP_PASS=2, XDP_TX=3) 125 | 126 | To export the processed packets in pcap traces, add the *-O* option to the command line arguments. It will produce four different traces in which the processed packets are grouped by return code. 127 | 128 | ## 5. Execute the *warped* use case 129 | 130 | To execute the same program with the Warp Engine, just provide the match-action table JSON file to the command line arguments: 131 | 132 | $ ./hXDP_sim --mat usecase_mat.json ... 133 | 134 | For example, for the l2acl use case: 135 | 136 | $ ./vm/hXDP_sim --mat use_cases/l2_acl/l2acl_mat.json --maps use_cases/l2_acl/l2acl_maps.json --pcap use_cases/l2_acl/l2acl.pcap -e use_cases/l2_acl/l2acl_map_entries.json -l 1 use_cases/l2_acl/l2acl.bin 137 | 138 | which produces the following output: 139 | 140 | hXDP_sim.c:514: info: In function main: Packet #1 141 | match_unit.c:584: info: In function lookup_entry: Matched entry number: 0 142 | hXDP_sim.c:529: warning: In function main: Instructions count: 0 143 | hXDP_sim.c:567: info: In function main: return 0x1 144 | 145 | hXDP_sim.c:514: info: In function main: Packet #2 146 | match_unit.c:584: info: In function lookup_entry: Matched entry number: 1 147 | ubpf_vm.c:783: info: In function ubpf_exec: Instructions count: 6 148 | hXDP_sim.c:567: info: In function main: return 0x2 149 | 150 | hXDP_sim.c:514: info: In function main: Packet #3 151 | match_unit.c:584: info: In function lookup_entry: Matched entry number: 2 152 | hXDP_sim.c:529: warning: In function main: Instructions count: 0 153 | hXDP_sim.c:567: info: In function main: return 0x2 154 | 155 | hXDP_sim.c:514: info: In function main: Packet #4 156 | match_unit.c:584: info: In function lookup_entry: Matched entry number: 1 157 | ubpf_vm.c:783: info: In function ubpf_exec: Instructions count: 5 158 | hXDP_sim.c:567: info: In function main: return 0x1 159 | 160 | We obtain the same information as before, but with the addition of the ID of the entry matched in the match-action table. 161 | 162 | The comparison between the "vanilla" and the "warped" number of instructions gives the results in Figure 5 of the paper. 163 | 164 | ## IMPORTANT NOTES! 165 | 166 | ### Katran 167 | 168 | For Katran, we suggest using the *katran.bin* and *katran_maps.json* provided (skip *readelf.py* step). To generate "MAP in MAP" table, it is necessary to manually write a JSON entry for the inner map since that information is not contained in the ELF. In the provided maps JSON file, the inner map is already inserted. 169 | -------------------------------------------------------------------------------- /ubpf/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /ubpf/readelf.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import lief 4 | from elftools.elf.elffile import ELFFile 5 | from elftools.elf.relocation import RelocationSection 6 | 7 | import sys 8 | import json 9 | 10 | # from hxdp_compiler.maps import BPFMap, BPFProgramMaps 11 | # from hxdp_compiler.packer_unpacker import BPF_INSN_SZ_B 12 | 13 | BPF_INSN_SZ_B = 8 14 | 15 | INSTR_REGEX = '([A-Fa-f0-9]{2}( )){7}([A-Fa-f0-9]{2})(( )([A-Fa-f0-9]{2}( )){7}([A-Fa-f0-9]{2}))?' 16 | COMMENTS_REGEX = '(;).*?' 17 | 18 | MAPS_DEF_STRUCT_FIELD_SZ_B = 4 19 | 20 | class ELFParsingError(Exception): 21 | pass 22 | 23 | 24 | def read_file_elf(filename, secname): 25 | # parse file as elf, 'allocate' maps file descriptors and returns the list of instructions as integers, 26 | # and the list of str mnemonics 27 | 28 | maps = [] # maps defined by the program 29 | tb_relocated = [] # instructions accessing maps 30 | 31 | with open(filename, 'rb') as f: 32 | elffile = ELFFile(f) 33 | symtab = elffile.get_section_by_name(".symtab") 34 | symtab_syms = list(symtab.iter_symbols()) 35 | 36 | strtab = elffile.get_section_by_name(".strtab") 37 | 38 | reladyn_name = ".rel" + secname 39 | reladyn = elffile.get_section_by_name(reladyn_name) 40 | 41 | # 1. parse maps relocation section, obtaining instructions to be modified & used maps 42 | insn_orig_pos_to_map_offset = {} # insn_orig_pos: offset inside maps section 43 | map_to_offsets = {} 44 | map_names = {} 45 | if isinstance(reladyn, RelocationSection): 46 | for reloc in reladyn.iter_relocations(): 47 | idx = int(reloc['r_offset'] / BPF_INSN_SZ_B) # instruction original position 48 | insn_orig_pos_to_map_offset[idx] = symtab_syms[reloc['r_info_sym']]['st_value'] 49 | map_id = symtab_syms[reloc['r_info_sym']]['st_value'] 50 | if map_id not in map_to_offsets: 51 | map_to_offsets[map_id] = [] 52 | map_to_offsets[map_id].append(idx) 53 | 54 | name_off = symtab_syms[reloc['r_info_sym']]['st_name'] 55 | map_names[map_id] = strtab.get_string(name_off) 56 | 57 | # 1-b. parse maps section 58 | maps_sec = elffile.get_section_by_name('maps') 59 | maps_sec = elffile.get_section_by_name('.maps') if maps_sec is None else maps_sec 60 | if maps_sec is None: 61 | raise ELFParsingError("invalid ELF file: found relocation sec %s but no maps section" % reladyn_name) 62 | 63 | for mid, map_off in enumerate(set(insn_orig_pos_to_map_offset.values())): 64 | maps_data = maps_sec.data() 65 | type = int.from_bytes(maps_data[map_off:map_off + MAPS_DEF_STRUCT_FIELD_SZ_B], byteorder='little') 66 | key_sz = int.from_bytes( 67 | maps_data[map_off + MAPS_DEF_STRUCT_FIELD_SZ_B:map_off + 2 * MAPS_DEF_STRUCT_FIELD_SZ_B], 68 | byteorder='little') 69 | value_sz = int.from_bytes( 70 | maps_data[map_off + 2 * MAPS_DEF_STRUCT_FIELD_SZ_B:map_off + 3 * MAPS_DEF_STRUCT_FIELD_SZ_B], 71 | byteorder='little') 72 | max_entries = int.from_bytes( 73 | maps_data[map_off + 3 * MAPS_DEF_STRUCT_FIELD_SZ_B:map_off + 4 * MAPS_DEF_STRUCT_FIELD_SZ_B], 74 | byteorder='little') 75 | 76 | maps.append({"id": mid, 77 | "offsets": map_to_offsets[map_off], 78 | "type": type, 79 | "key_size": key_sz, 80 | "value_size": value_sz, 81 | "max_entries": max_entries, 82 | "name": map_names[map_off]}) 83 | 84 | # 3. parse instruction section 85 | elf = lief.parse(filename) 86 | code = elf.get_section(secname) 87 | 88 | prog_bin = [] 89 | for i in range(0, len(code.content), BPF_INSN_SZ_B): 90 | ins = int.from_bytes(code.content[i:i + BPF_INSN_SZ_B], byteorder='big') 91 | 92 | idx = int(i / BPF_INSN_SZ_B) 93 | if idx in insn_orig_pos_to_map_offset: 94 | tb_relocated.append(idx) 95 | # maps.add_map_reference(insn_orig_pos_to_map_offset[idx], idx) 96 | 97 | prog_bin.append(ins) 98 | 99 | return prog_bin, tb_relocated, maps 100 | 101 | 102 | def read_file_dump(filename: str): 103 | # parse file and returns the list of instructions as integers, and the list of str mnemonics 104 | 105 | program_bin = [] 106 | program_str = [] 107 | for line in open(filename, 'r'): 108 | if not re.search(COMMENTS_REGEX, line): # ignore comment line 109 | instr_match = re.search(INSTR_REGEX, line) 110 | 111 | if instr_match: 112 | instr_s = line[instr_match.regs[0][1]:].lstrip().replace("\n", "") 113 | label = re.search(r"(<)\w+(>)", instr_s) 114 | if label: 115 | instr_s = instr_s[:label.regs[0][0]] 116 | 117 | program_str.append(instr_s) 118 | 119 | program_bin.append(int(instr_match.group(0).replace(' ', '')[:16], 16)) 120 | 121 | if len(instr_match.group(0).replace(' ', '')) > 16: 122 | program_bin.append(0) 123 | program_str.append("NOP") 124 | 125 | return program_bin, program_str 126 | 127 | 128 | def print_line(line): 129 | bins = "{0:64b}".format(line).replace(" ", "0") 130 | print("|" + bins[:8] + "|" + bins[8:12] + "|" + bins[12:16] + "|" + bins[16:32] + "|" + bins[32:64] + "|") 131 | 132 | 133 | filename = sys.argv[1] 134 | 135 | secname = sys.argv[3] 136 | 137 | prog_bin, tb_relocated, maps = read_file_elf(filename, secname) 138 | 139 | print(tb_relocated) 140 | print(maps) 141 | 142 | file = open(sys.argv[2]+".bin", "wb") 143 | 144 | for ins in prog_bin: 145 | file.write(int.to_bytes(ins, BPF_INSN_SZ_B, byteorder="big")) 146 | 147 | file.close() 148 | 149 | json_file = open(sys.argv[2]+"_maps.json", "w") 150 | json_file.write(json.dumps(maps, indent=4)) 151 | json_file.close() 152 | 153 | print("Saved program in "+sys.argv[2]+".bin and map definitions in "+sys.argv[2]+"_maps.json") 154 | -------------------------------------------------------------------------------- /ubpf/requirements.txt: -------------------------------------------------------------------------------- 1 | # pypi version of parcon does not support python3 2 | git+https://github.com/javawizard/parcon 3 | nose ~= 1.3.1 4 | pyelftools ~= 0.27 5 | -------------------------------------------------------------------------------- /ubpf/src/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Big Switch Networks, Inc 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | CFLAGS := -Wall -Werror -Iinc -O0 -g -Wunused-parameter 16 | LDLIBS := -lm -lpcap 17 | 18 | INSTALL ?= install 19 | DESTDIR = 20 | PREFIX ?= /usr/local 21 | 22 | ifeq ($(COVERAGE),1) 23 | CFLAGS += -fprofile-arcs -ftest-coverage 24 | LDFLAGS += -fprofile-arcs 25 | endif 26 | 27 | ifeq ($(ASAN),1) 28 | CFLAGS += -fsanitize=address 29 | LDFLAGS += -fsanitize=address 30 | endif 31 | 32 | all: clean libubpf.a hXDP_sim 33 | 34 | sclog4c.o: sclog4c.c 35 | 36 | lookup3.o: lookup3.c lookup3.h 37 | 38 | ubpf_array.o: ubpf_array.c 39 | 40 | ubpf_hashmap.o: ubpf_hashmap.c ubpf_hashmap.h 41 | 42 | ubpf_lpm.o: ubpf_lpm.c ubpf_lpm.h 43 | 44 | helper_functions.o: helper_functions.c helper_functions.h 45 | 46 | libubpf.a: ubpf_vm.o sclog4c.o lookup3.o ubpf_array.o helper_functions.o ubpf_hashmap.o ubpf_lpm.o 47 | ar rc $@ $^ 48 | 49 | cJSON.o: cJSON.c 50 | 51 | match_unit.o: match_unit.c 52 | 53 | hXDP_sim: hXDP_sim.o cJSON.o match_unit.o libubpf.a 54 | 55 | install: 56 | $(INSTALL) -d $(DESTDIR)$(PREFIX)/lib 57 | $(INSTALL) -m 644 libubpf.a $(DESTDIR)$(PREFIX)/lib 58 | $(INSTALL) -d $(DESTDIR)$(PREFIX)/include 59 | $(INSTALL) -m 644 inc/ubpf.h $(DESTDIR)$(PREFIX)/include 60 | 61 | clean: 62 | rm -f test libubpf.a *.o hXDP_sim 63 | -------------------------------------------------------------------------------- /ubpf/src/cJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef cJSON__h 24 | #define cJSON__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) 32 | #define __WINDOWS__ 33 | #endif 34 | 35 | #ifdef __WINDOWS__ 36 | 37 | /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: 38 | 39 | CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols 40 | CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) 41 | CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol 42 | 43 | For *nix builds that support visibility attribute, you can define similar behavior by 44 | 45 | setting default visibility to hidden by adding 46 | -fvisibility=hidden (for gcc) 47 | or 48 | -xldscope=hidden (for sun cc) 49 | to CFLAGS 50 | 51 | then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does 52 | 53 | */ 54 | 55 | #define CJSON_CDECL __cdecl 56 | #define CJSON_STDCALL __stdcall 57 | 58 | /* export symbols by default, this is necessary for copy pasting the C and header file */ 59 | #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) 60 | #define CJSON_EXPORT_SYMBOLS 61 | #endif 62 | 63 | #if defined(CJSON_HIDE_SYMBOLS) 64 | #define CJSON_PUBLIC(type) type CJSON_STDCALL 65 | #elif defined(CJSON_EXPORT_SYMBOLS) 66 | #define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL 67 | #elif defined(CJSON_IMPORT_SYMBOLS) 68 | #define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL 69 | #endif 70 | #else /* !__WINDOWS__ */ 71 | #define CJSON_CDECL 72 | #define CJSON_STDCALL 73 | 74 | #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) 75 | #define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type 76 | #else 77 | #define CJSON_PUBLIC(type) type 78 | #endif 79 | #endif 80 | 81 | /* project version */ 82 | #define CJSON_VERSION_MAJOR 1 83 | #define CJSON_VERSION_MINOR 7 84 | #define CJSON_VERSION_PATCH 14 85 | 86 | #include 87 | 88 | /* cJSON Types: */ 89 | #define cJSON_Invalid (0) 90 | #define cJSON_False (1 << 0) 91 | #define cJSON_True (1 << 1) 92 | #define cJSON_NULL (1 << 2) 93 | #define cJSON_Number (1 << 3) 94 | #define cJSON_String (1 << 4) 95 | #define cJSON_Array (1 << 5) 96 | #define cJSON_Object (1 << 6) 97 | #define cJSON_Raw (1 << 7) /* raw json */ 98 | 99 | #define cJSON_IsReference 256 100 | #define cJSON_StringIsConst 512 101 | 102 | /* The cJSON structure: */ 103 | typedef struct cJSON 104 | { 105 | /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 106 | struct cJSON *next; 107 | struct cJSON *prev; 108 | /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 109 | struct cJSON *child; 110 | 111 | /* The type of the item, as above. */ 112 | int type; 113 | 114 | /* The item's string, if type==cJSON_String and type == cJSON_Raw */ 115 | char *valuestring; 116 | /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ 117 | int valueint; 118 | /* The item's number, if type==cJSON_Number */ 119 | double valuedouble; 120 | 121 | /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 122 | char *string; 123 | } cJSON; 124 | 125 | typedef struct cJSON_Hooks 126 | { 127 | /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ 128 | void *(CJSON_CDECL *malloc_fn)(size_t sz); 129 | void (CJSON_CDECL *free_fn)(void *ptr); 130 | } cJSON_Hooks; 131 | 132 | typedef int cJSON_bool; 133 | 134 | /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. 135 | * This is to prevent stack overflows. */ 136 | #ifndef CJSON_NESTING_LIMIT 137 | #define CJSON_NESTING_LIMIT 1000 138 | #endif 139 | 140 | /* returns the version of cJSON as a string */ 141 | CJSON_PUBLIC(const char*) cJSON_Version(void); 142 | 143 | /* Supply malloc, realloc and free functions to cJSON */ 144 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); 145 | 146 | /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ 147 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ 148 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); 149 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); 150 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 151 | /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ 152 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); 153 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); 154 | 155 | /* Render a cJSON entity to text for transfer/storage. */ 156 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); 157 | /* Render a cJSON entity to text for transfer/storage without any formatting. */ 158 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); 159 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 160 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); 161 | /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ 162 | /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ 163 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); 164 | /* Delete a cJSON entity and all subentities. */ 165 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); 166 | 167 | /* Returns the number of items in an array (or object). */ 168 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); 169 | /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ 170 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); 171 | /* Get item "string" from object. Case insensitive. */ 172 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); 173 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); 174 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); 175 | /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ 176 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); 177 | 178 | /* Check item type and return its value */ 179 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); 180 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); 181 | 182 | /* These functions check the type of an item */ 183 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); 184 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); 185 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); 186 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); 187 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); 188 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); 189 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); 190 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); 191 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); 192 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); 193 | 194 | /* These calls create a cJSON item of the appropriate type. */ 195 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); 196 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); 197 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); 198 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); 199 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); 200 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); 201 | /* raw json */ 202 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); 203 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); 204 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); 205 | 206 | /* Create a string where valuestring references a string so 207 | * it will not be freed by cJSON_Delete */ 208 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); 209 | /* Create an object/array that only references it's elements so 210 | * they will not be freed by cJSON_Delete */ 211 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); 212 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); 213 | 214 | /* These utilities create an Array of count items. 215 | * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ 216 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); 217 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); 218 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); 219 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); 220 | 221 | /* Append item to the specified array/object. */ 222 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); 223 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); 224 | /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. 225 | * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before 226 | * writing to `item->string` */ 227 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); 228 | /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ 229 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 230 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); 231 | 232 | /* Remove/Detach items from Arrays/Objects. */ 233 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); 234 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); 235 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); 236 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); 237 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); 238 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); 239 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); 240 | 241 | /* Update array items. */ 242 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ 243 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); 244 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); 245 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 246 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); 247 | 248 | /* Duplicate a cJSON item */ 249 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); 250 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 251 | * need to be released. With recurse!=0, it will duplicate any children connected to the item. 252 | * The item->next and ->prev pointers are always zero on return from Duplicate. */ 253 | /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. 254 | * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ 255 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); 256 | 257 | /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. 258 | * The input pointer json cannot point to a read-only address area, such as a string constant, 259 | * but should point to a readable and writable adress area. */ 260 | CJSON_PUBLIC(void) cJSON_Minify(char *json); 261 | 262 | /* Helper functions for creating and adding items to an object at the same time. 263 | * They return the added item or NULL on failure. */ 264 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); 265 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); 266 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); 267 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); 268 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); 269 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); 270 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); 271 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); 272 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); 273 | 274 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 275 | #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) 276 | /* helper for the cJSON_SetNumberValue macro */ 277 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); 278 | #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) 279 | /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ 280 | CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); 281 | 282 | /* Macro for iterating over an array or object */ 283 | #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) 284 | 285 | /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ 286 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size); 287 | CJSON_PUBLIC(void) cJSON_free(void *object); 288 | 289 | #ifdef __cplusplus 290 | } 291 | #endif 292 | 293 | #endif 294 | -------------------------------------------------------------------------------- /ubpf/src/cJSON.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/cJSON.o -------------------------------------------------------------------------------- /ubpf/src/ebpf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Big Switch 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_H 18 | #define EBPF_H 19 | 20 | #include 21 | 22 | /* eBPF definitions */ 23 | 24 | struct ebpf_inst { 25 | uint8_t opcode; 26 | uint8_t dst : 4; 27 | uint8_t src : 4; 28 | int16_t offset; 29 | int32_t imm; 30 | }; 31 | 32 | #define EBPF_CLS_MASK 0x07 33 | #define EBPF_ALU_OP_MASK 0xf0 34 | 35 | #define EBPF_CLS_LD 0x00 36 | #define EBPF_CLS_LDX 0x01 37 | #define EBPF_CLS_ST 0x02 38 | #define EBPF_CLS_STX 0x03 39 | #define EBPF_CLS_ALU 0x04 40 | #define EBPF_CLS_JMP 0x05 41 | #define EBPF_CLS_ALU64 0x07 42 | 43 | #define EBPF_SRC_IMM 0x00 44 | #define EBPF_SRC_REG 0x08 45 | 46 | #define EBPF_SIZE_W 0x00 47 | #define EBPF_SIZE_H 0x08 48 | #define EBPF_SIZE_B 0x10 49 | #define EBPF_SIZE_DW 0x18 50 | 51 | /* Other memory modes are not yet supported */ 52 | #define EBPF_MODE_IMM 0x00 53 | #define EBPF_MODE_MEM 0x60 54 | 55 | #define EBPF_OP_ADD_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0x00) 56 | #define EBPF_OP_ADD_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0x00) 57 | #define EBPF_OP_SUB_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0x10) 58 | #define EBPF_OP_SUB_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0x10) 59 | #define EBPF_OP_MUL_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0x20) 60 | #define EBPF_OP_MUL_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0x20) 61 | #define EBPF_OP_DIV_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0x30) 62 | #define EBPF_OP_DIV_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0x30) 63 | #define EBPF_OP_OR_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0x40) 64 | #define EBPF_OP_OR_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0x40) 65 | #define EBPF_OP_AND_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0x50) 66 | #define EBPF_OP_AND_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0x50) 67 | #define EBPF_OP_LSH_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0x60) 68 | #define EBPF_OP_LSH_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0x60) 69 | #define EBPF_OP_RSH_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0x70) 70 | #define EBPF_OP_RSH_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0x70) 71 | #define EBPF_OP_NEG (EBPF_CLS_ALU|0x80) 72 | #define EBPF_OP_MOD_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0x90) 73 | #define EBPF_OP_MOD_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0x90) 74 | #define EBPF_OP_XOR_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0xa0) 75 | #define EBPF_OP_XOR_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0xa0) 76 | #define EBPF_OP_MOV_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0xb0) 77 | #define EBPF_OP_MOV_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0xb0) 78 | #define EBPF_OP_ARSH_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|0xc0) 79 | #define EBPF_OP_ARSH_REG (EBPF_CLS_ALU|EBPF_SRC_REG|0xc0) 80 | #define EBPF_OP_LE (EBPF_CLS_ALU|EBPF_SRC_IMM|0xd0) 81 | #define EBPF_OP_BE (EBPF_CLS_ALU|EBPF_SRC_REG|0xd0) 82 | 83 | #define EBPF_OP_ADD64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0x00) 84 | #define EBPF_OP_ADD64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0x00) 85 | #define EBPF_OP_SUB64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0x10) 86 | #define EBPF_OP_SUB64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0x10) 87 | #define EBPF_OP_MUL64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0x20) 88 | #define EBPF_OP_MUL64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0x20) 89 | #define EBPF_OP_DIV64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0x30) 90 | #define EBPF_OP_DIV64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0x30) 91 | #define EBPF_OP_OR64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0x40) 92 | #define EBPF_OP_OR64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0x40) 93 | #define EBPF_OP_AND64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0x50) 94 | #define EBPF_OP_AND64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0x50) 95 | #define EBPF_OP_LSH64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0x60) 96 | #define EBPF_OP_LSH64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0x60) 97 | #define EBPF_OP_RSH64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0x70) 98 | #define EBPF_OP_RSH64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0x70) 99 | #define EBPF_OP_NEG64 (EBPF_CLS_ALU64|0x80) 100 | #define EBPF_OP_MOD64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0x90) 101 | #define EBPF_OP_MOD64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0x90) 102 | #define EBPF_OP_XOR64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0xa0) 103 | #define EBPF_OP_XOR64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0xa0) 104 | #define EBPF_OP_MOV64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0xb0) 105 | #define EBPF_OP_MOV64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0xb0) 106 | #define EBPF_OP_ARSH64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|0xc0) 107 | #define EBPF_OP_ARSH64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|0xc0) 108 | 109 | #define EBPF_OP_LDXW (EBPF_CLS_LDX|EBPF_MODE_MEM|EBPF_SIZE_W) 110 | #define EBPF_OP_LDXH (EBPF_CLS_LDX|EBPF_MODE_MEM|EBPF_SIZE_H) 111 | #define EBPF_OP_LDXB (EBPF_CLS_LDX|EBPF_MODE_MEM|EBPF_SIZE_B) 112 | #define EBPF_OP_LDXDW (EBPF_CLS_LDX|EBPF_MODE_MEM|EBPF_SIZE_DW) 113 | #define EBPF_OP_STW (EBPF_CLS_ST|EBPF_MODE_MEM|EBPF_SIZE_W) 114 | #define EBPF_OP_STH (EBPF_CLS_ST|EBPF_MODE_MEM|EBPF_SIZE_H) 115 | #define EBPF_OP_STB (EBPF_CLS_ST|EBPF_MODE_MEM|EBPF_SIZE_B) 116 | #define EBPF_OP_STDW (EBPF_CLS_ST|EBPF_MODE_MEM|EBPF_SIZE_DW) 117 | #define EBPF_OP_STXW (EBPF_CLS_STX|EBPF_MODE_MEM|EBPF_SIZE_W) 118 | #define EBPF_OP_STXH (EBPF_CLS_STX|EBPF_MODE_MEM|EBPF_SIZE_H) 119 | #define EBPF_OP_STXB (EBPF_CLS_STX|EBPF_MODE_MEM|EBPF_SIZE_B) 120 | #define EBPF_OP_STXDW (EBPF_CLS_STX|EBPF_MODE_MEM|EBPF_SIZE_DW) 121 | #define EBPF_OP_LDDW (EBPF_CLS_LD|EBPF_MODE_IMM|EBPF_SIZE_DW) 122 | 123 | #define EBPF_OP_JA (EBPF_CLS_JMP|0x00) 124 | #define EBPF_OP_JEQ_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x10) 125 | #define EBPF_OP_JEQ_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x10) 126 | #define EBPF_OP_JGT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x20) 127 | #define EBPF_OP_JGT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x20) 128 | #define EBPF_OP_JGE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x30) 129 | #define EBPF_OP_JGE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x30) 130 | #define EBPF_OP_JSET_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x40) 131 | #define EBPF_OP_JSET_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x40) 132 | #define EBPF_OP_JNE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x50) 133 | #define EBPF_OP_JNE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x50) 134 | #define EBPF_OP_JSGT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x60) 135 | #define EBPF_OP_JSGT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x60) 136 | #define EBPF_OP_JSGE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x70) 137 | #define EBPF_OP_JSGE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x70) 138 | #define EBPF_OP_CALL (EBPF_CLS_JMP|0x80) 139 | #define EBPF_OP_EXIT (EBPF_CLS_JMP|0x90) 140 | #define EBPF_OP_JLT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0xa0) 141 | #define EBPF_OP_JLT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0xa0) 142 | #define EBPF_OP_JLE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0xb0) 143 | #define EBPF_OP_JLE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0xb0) 144 | #define EBPF_OP_JSLT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0xc0) 145 | #define EBPF_OP_JSLT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0xc0) 146 | #define EBPF_OP_JSLE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0xd0) 147 | #define EBPF_OP_JSLE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0xd0) 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /ubpf/src/flow_cache.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Axbryd 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 "flow_cache.h" 19 | #include "ubpf_int.h" 20 | #include "inc/sclog4c.h" 21 | 22 | static inline void 23 | dump_hashtable(struct cache_entry *flows) { 24 | struct cache_entry *element, *tmp; 25 | logm(SL4C_DEBUG, "Dumping hashtable"); 26 | if (sclog4c_level <= SL4C_DEBUG) { 27 | HASH_ITER(hh, flows, element, tmp) { 28 | for (int i=0; ikey_len; i++) { 29 | fprintf(stderr,"%02x", element->key[i]); 30 | } 31 | 32 | fprintf(stderr," hash value: 0x%08x", element->hh.hashv); 33 | 34 | fprintf(stderr, "\n"); 35 | } 36 | } 37 | } 38 | 39 | static inline struct cache_entry * 40 | add_cache_entry_to_hash(struct cache_entry** flows, 41 | u_char *in_key, size_t key_len) 42 | { 43 | struct cache_entry *cache_entry = malloc(sizeof(struct cache_entry)); 44 | cache_entry->ctx = malloc(sizeof(struct map_context)); 45 | cache_entry->key = malloc(key_len); 46 | 47 | cache_entry->key_len = key_len; 48 | 49 | memcpy(cache_entry->key, in_key, key_len); 50 | 51 | cache_entry->prev = NULL; 52 | cache_entry->next = NULL; 53 | 54 | if (sclog4c_level <= SL4C_DEBUG) { 55 | logm(SL4C_DEBUG, "Adding a new key to the hash, key len is %lu\n", key_len); 56 | 57 | for (int i=0; ikey_len; i++) { 58 | fprintf(stderr,"%02x", cache_entry->key[i]); 59 | } 60 | fprintf(stderr, "\n\n"); 61 | } 62 | 63 | HASH_ADD_KEYPTR(hh, *flows, cache_entry->key, key_len, cache_entry); 64 | 65 | dump_hashtable(*flows); 66 | 67 | return cache_entry; 68 | } 69 | 70 | static inline struct cache_entry * 71 | find_cache_entry_in_hash(struct cache_entry *flows, u_char *in_key, size_t key_len) 72 | { 73 | struct cache_entry *found = NULL; 74 | 75 | if (sclog4c_level <= SL4C_DEBUG) { 76 | logm(SL4C_DEBUG, "FINDING cache entry in the hash\n------->"); 77 | 78 | for (int i=0; icount == 0) 96 | return true; 97 | else 98 | return false; 99 | } 100 | 101 | bool 102 | cache_full(struct cache_queue *cache) 103 | { 104 | if (cache->count == cache->nb_frames) 105 | return true; 106 | else 107 | return false; 108 | } 109 | 110 | void 111 | dequeue(struct cache_queue *cache) 112 | { 113 | if (cache_empty(cache)) 114 | return; 115 | 116 | if (cache->front == cache->rear) 117 | cache->front = NULL; 118 | 119 | struct cache_entry *tmp = cache->rear; 120 | cache->rear = cache->rear->prev; 121 | 122 | if (cache->rear) 123 | cache->rear->next = NULL; 124 | 125 | tmp->next = NULL; 126 | tmp->prev = NULL; 127 | 128 | cache->count--; 129 | } 130 | 131 | void 132 | enqueue(struct cache_queue *cache, struct cache_entry *req_entry) 133 | { 134 | if (cache_full(cache)) { 135 | dequeue(cache); 136 | } 137 | 138 | req_entry->next = cache->front; 139 | 140 | if (cache_empty(cache)) { 141 | cache->rear = cache->front = req_entry; 142 | } else { 143 | cache->front->prev = req_entry; 144 | cache->front = req_entry; 145 | } 146 | 147 | cache->count++; 148 | } 149 | 150 | enum cache_result 151 | reference_cache(struct cache_queue *cache, 152 | struct cache_entry **flows, 153 | u_char *key, size_t key_len, 154 | struct cache_entry **out) 155 | { 156 | struct cache_entry *req_entry = NULL; 157 | 158 | req_entry = find_cache_entry_in_hash(*flows, key, key_len); 159 | 160 | *out = req_entry; 161 | 162 | // If requested entry is not in hash 163 | if (!req_entry) { 164 | req_entry = add_cache_entry_to_hash(flows, key, key_len); 165 | 166 | *out = req_entry; 167 | 168 | enqueue(cache, req_entry); 169 | 170 | return NOT_IN_HASH; 171 | } 172 | // If req_entry is not in the cache 173 | else if (req_entry->prev == NULL && req_entry->next == NULL && cache->front != req_entry) { 174 | dequeue(cache); 175 | 176 | enqueue(cache, req_entry); 177 | 178 | return NOT_IN_CACHE; 179 | } 180 | // if requested entry is in cache but not at front 181 | else if (req_entry != cache->front) { 182 | // Unlink requested entry 183 | req_entry->prev->next = req_entry->next; 184 | if (req_entry->next) 185 | req_entry->next->prev = req_entry->prev; 186 | 187 | if (req_entry == cache->rear) { 188 | cache->rear = req_entry->prev; 189 | cache->rear->next = NULL; 190 | } 191 | 192 | req_entry->next = cache->front; 193 | req_entry->prev = NULL; 194 | 195 | req_entry->next->prev = req_entry; 196 | 197 | cache->front = req_entry; 198 | 199 | return NOT_IN_CACHE_FRONT; 200 | } else { // Requested entry is in cache at first position 201 | return IN_CACHE_FRONT; 202 | } 203 | } 204 | 205 | struct cache_queue * 206 | create_cache(unsigned int size) 207 | { 208 | struct cache_queue *cache = malloc(sizeof(struct cache_queue)); 209 | 210 | cache->count = 0; 211 | cache->front = cache->rear = NULL; 212 | 213 | cache->nb_frames = size; 214 | 215 | return cache; 216 | } -------------------------------------------------------------------------------- /ubpf/src/flow_cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Axbryd 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 UBPF_FLOW_CACHE_H 18 | #define UBPF_FLOW_CACHE_H 19 | 20 | #include "uthash.h" 21 | #include "ubpf.h" 22 | 23 | #define CACHE_SIZE 8 24 | #define HASH_SIZE 1<<20 25 | 26 | struct cache_entry { 27 | u_char *key; 28 | size_t key_len; 29 | struct map_context *ctx; 30 | struct cache_entry *prev, *next; 31 | UT_hash_handle hh; 32 | }; 33 | 34 | struct cache_queue { 35 | unsigned int count; 36 | unsigned int nb_frames; 37 | struct cache_entry *front, *rear; 38 | }; 39 | 40 | enum cache_result { 41 | NOT_IN_HASH = 0, 42 | NOT_IN_CACHE, 43 | NOT_IN_CACHE_FRONT, 44 | IN_CACHE_FRONT 45 | }; 46 | 47 | enum cache_result 48 | reference_cache(struct cache_queue *cache, 49 | struct cache_entry **flows, 50 | u_char *key, size_t key_len, 51 | struct cache_entry **out); 52 | 53 | struct cache_queue * 54 | create_cache(unsigned int size); 55 | 56 | 57 | #endif //UBPF_FLOW_CACHE_H 58 | -------------------------------------------------------------------------------- /ubpf/src/hXDP_sim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/hXDP_sim -------------------------------------------------------------------------------- /ubpf/src/hXDP_sim.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/hXDP_sim.o -------------------------------------------------------------------------------- /ubpf/src/helper_functions.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Axbryd 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 | #include 19 | #include "helper_functions.h" 20 | #include "ubpf_hashmap.h" 21 | 22 | struct ubpf_func_proto ubpf_map_lookup_proto = { 23 | .func = (ext_func)ubpf_map_lookup, 24 | .arg_types = { 25 | MAP_PTR, 26 | PKT_PTR | MAP_VALUE_PTR | STACK_PTR | UNKNOWN, 27 | 0xff, 28 | 0xff, 29 | 0xff, 30 | }, 31 | .arg_sizes = { 32 | 0xff, 33 | SIZE_MAP_KEY, 34 | 0xff, 35 | 0xff, 36 | 0xff, 37 | }, 38 | .ret = MAP_VALUE_PTR | NULL_VALUE, 39 | }; 40 | 41 | void * 42 | ubpf_map_lookup(const struct ubpf_map *map, void *key) 43 | { 44 | if (!map) { 45 | return NULL; 46 | } 47 | if (!map->ops.map_lookup) { 48 | return NULL; 49 | } 50 | if (!key) { 51 | return NULL; 52 | } 53 | return map->ops.map_lookup(map, key); 54 | } 55 | 56 | struct ubpf_func_proto ubpf_map_update_proto = { 57 | .func = (ext_func)ubpf_map_update, 58 | .arg_types = { 59 | MAP_PTR, 60 | PKT_PTR | MAP_VALUE_PTR | STACK_PTR, 61 | PKT_PTR | MAP_VALUE_PTR | STACK_PTR, 62 | 0xff, 63 | 0xff, 64 | }, 65 | .arg_sizes = { 66 | 0xff, 67 | SIZE_MAP_KEY, 68 | SIZE_MAP_VALUE, 69 | 0xff, 70 | 0xff, 71 | }, 72 | .ret = UNKNOWN, 73 | }; 74 | 75 | int 76 | ubpf_map_update(struct ubpf_map *map, const void *key, void *item) 77 | { 78 | if (!map) { 79 | return -1; 80 | } 81 | if (!map->ops.map_update) { 82 | return -2; 83 | } 84 | if (!key) { 85 | return -3; 86 | } 87 | if (!item) { 88 | return -4; 89 | } 90 | return map->ops.map_update(map, key, item); 91 | } 92 | 93 | struct ubpf_func_proto ubpf_map_add_proto = { 94 | .func = (ext_func)ubpf_map_add, 95 | .arg_types = { 96 | MAP_PTR, 97 | PKT_PTR | MAP_VALUE_PTR | STACK_PTR, 98 | 0xff, 99 | 0xff, 100 | 0xff, 101 | }, 102 | .arg_sizes = { 103 | 0xff, 104 | SIZE_MAP_VALUE, 105 | 0xff, 106 | 0xff, 107 | 0xff, 108 | }, 109 | .ret = UNKNOWN, 110 | }; 111 | 112 | int 113 | ubpf_map_add(struct ubpf_map *map, void *item) 114 | { 115 | if (!map) { 116 | return -1; 117 | } 118 | if (!map->ops.map_add) { 119 | return -2; 120 | } 121 | if (!item) { 122 | return -3; 123 | } 124 | return map->ops.map_add(map, item); 125 | } 126 | 127 | struct ubpf_func_proto ubpf_map_delete_proto = { 128 | .func = (ext_func)ubpf_map_delete, 129 | .arg_types = { 130 | MAP_PTR, 131 | PKT_PTR | MAP_VALUE_PTR | STACK_PTR, 132 | 0xff, 133 | 0xff, 134 | 0xff, 135 | }, 136 | .arg_sizes = { 137 | 0xff, 138 | SIZE_MAP_KEY, 139 | 0xff, 140 | 0xff, 141 | 0xff, 142 | }, 143 | .ret = UNKNOWN, 144 | }; 145 | 146 | int 147 | ubpf_map_delete(struct ubpf_map *map, const void *key) 148 | { 149 | if (!map) { 150 | return -1; 151 | } 152 | if (!map->ops.map_delete) { 153 | return -2; 154 | } 155 | if (!key) { 156 | return -3; 157 | } 158 | return map->ops.map_delete(map, key); 159 | } 160 | 161 | struct ubpf_func_proto ubpf_time_get_ns_proto = { 162 | .func = (ext_func)ubpf_time_get_ns, 163 | .arg_types = { 164 | 0xff, 165 | 0xff, 166 | 0xff, 167 | 0xff, 168 | 0xff, 169 | }, 170 | .arg_sizes = { 171 | 0xff, 172 | 0xff, 173 | 0xff, 174 | 0xff, 175 | 0xff, 176 | }, 177 | .ret = UNKNOWN, 178 | }; 179 | 180 | uint64_t 181 | ubpf_time_get_ns(void) 182 | { 183 | struct timespec curr_time = {0, 0}; 184 | uint64_t curr_time_ns = 0; 185 | clock_gettime(CLOCK_REALTIME, &curr_time); 186 | curr_time_ns = curr_time.tv_nsec + curr_time.tv_sec * 1.0e9; 187 | return curr_time_ns; 188 | } 189 | 190 | struct ubpf_func_proto ubpf_hash_proto = { 191 | .func = (ext_func)ubpf_hash, 192 | .arg_types = { 193 | PKT_PTR | MAP_VALUE_PTR | STACK_PTR, 194 | IMM, 195 | 0xff, 196 | 0xff, 197 | 0xff, 198 | }, 199 | .arg_sizes = { 200 | SIZE_PTR_MAX, 201 | SIZE_64, 202 | 0xff, 203 | 0xff, 204 | 0xff, 205 | }, 206 | .ret = UNKNOWN, 207 | }; 208 | 209 | uint32_t 210 | ubpf_hash(void *item, uint64_t size) 211 | { 212 | return hashlittle(item, (uint32_t)size, 0); 213 | } 214 | 215 | struct ubpf_func_proto ubpf_get_smp_processor_id_proto = { 216 | .func = (ext_func)ubpf_get_smp_processor_id, 217 | .arg_types = { 218 | 0xff, 219 | 0xff, 220 | 0xff, 221 | 0xff, 222 | 0xff, 223 | }, 224 | .arg_sizes = { 225 | 0xff, 226 | 0xff, 227 | 0xff, 228 | 0xff, 229 | 0xff, 230 | }, 231 | .ret = UNKNOWN, 232 | }; 233 | 234 | uint64_t 235 | ubpf_get_smp_processor_id() { 236 | return 0; 237 | } 238 | 239 | struct ubpf_func_proto ubpf_csum_diff_proto = { 240 | .func = (ext_func)ubpf_csum_diff, 241 | .arg_types = { 242 | PKT_PTR, 243 | IMM, 244 | PKT_PTR, 245 | IMM, 246 | IMM, 247 | }, 248 | .arg_sizes = { 249 | SIZE_PTR_MAX, 250 | SIZE_64, 251 | SIZE_PTR_MAX, 252 | SIZE_64, 253 | SIZE_64, 254 | }, 255 | .ret = UNKNOWN, 256 | }; 257 | 258 | static inline unsigned short from64to16(unsigned long x) 259 | { 260 | /* Using extract instructions is a bit more efficient 261 | than the original shift/bitmask version. */ 262 | 263 | union { 264 | unsigned long ul; 265 | unsigned int ui[2]; 266 | unsigned short us[4]; 267 | } in_v, tmp_v, out_v; 268 | 269 | in_v.ul = x; 270 | tmp_v.ul = (unsigned long) in_v.ui[0] + (unsigned long) in_v.ui[1]; 271 | 272 | /* Since the bits of tmp_v.sh[3] are going to always be zero, 273 | we don't have to bother to add that in. */ 274 | out_v.ul = (unsigned long) tmp_v.us[0] + (unsigned long) tmp_v.us[1] 275 | + (unsigned long) tmp_v.us[2]; 276 | 277 | /* Similarly, out_v.us[2] is always zero for the final add. */ 278 | return out_v.us[0] + out_v.us[1]; 279 | } 280 | 281 | 282 | static inline unsigned long do_csum(const unsigned char * buff, int len) 283 | { 284 | int odd, count; 285 | unsigned long result = 0; 286 | 287 | if (len <= 0) 288 | goto out; 289 | odd = 1 & (unsigned long) buff; 290 | if (odd) { 291 | result = *buff << 8; 292 | len--; 293 | buff++; 294 | } 295 | count = len >> 1; /* nr of 16-bit words.. */ 296 | if (count) { 297 | if (2 & (unsigned long) buff) { 298 | result += *(unsigned short *) buff; 299 | count--; 300 | len -= 2; 301 | buff += 2; 302 | } 303 | count >>= 1; /* nr of 32-bit words.. */ 304 | if (count) { 305 | if (4 & (unsigned long) buff) { 306 | result += *(unsigned int *) buff; 307 | count--; 308 | len -= 4; 309 | buff += 4; 310 | } 311 | count >>= 1; /* nr of 64-bit words.. */ 312 | if (count) { 313 | unsigned long carry = 0; 314 | do { 315 | unsigned long w = *(unsigned long *) buff; 316 | count--; 317 | buff += 8; 318 | result += carry; 319 | result += w; 320 | carry = (w > result); 321 | } while (count); 322 | result += carry; 323 | result = (result & 0xffffffff) + (result >> 32); 324 | } 325 | if (len & 4) { 326 | result += *(unsigned int *) buff; 327 | buff += 4; 328 | } 329 | } 330 | if (len & 2) { 331 | result += *(unsigned short *) buff; 332 | buff += 2; 333 | } 334 | } 335 | if (len & 1) 336 | result += *buff; 337 | result = from64to16(result); 338 | if (odd) 339 | result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); 340 | out: 341 | return result; 342 | } 343 | 344 | uint64_t 345 | csum_partial(const void *buff, int len, uint64_t seed) 346 | { 347 | unsigned int sum = (unsigned int) seed; 348 | unsigned int result = do_csum(buff, len); 349 | 350 | /* add in old sum, and carry.. */ 351 | result += sum; 352 | if (sum > result) 353 | result += 1; 354 | return (uint64_t)result; 355 | } 356 | 357 | uint64_t 358 | ubpf_csum_diff(uint64_t r1, uint64_t from_size, 359 | uint64_t r3, uint64_t to_size, uint64_t seed) { 360 | uint32_t *from = (uint32_t *) (long) r1; 361 | uint32_t *to = (uint32_t *) (long) r3; 362 | uint64_t diff_size = from_size + to_size; 363 | uint32_t diff[diff_size/ sizeof(uint32_t)]; 364 | 365 | int i, j = 0; 366 | 367 | for (i = 0; i < from_size / sizeof(uint32_t); i++, j++) 368 | diff[j] = ~from[i]; 369 | for (i = 0; i < to_size / sizeof(uint32_t); i++, j++) 370 | diff[j] = to[i]; 371 | 372 | return csum_partial(diff, diff_size, seed); 373 | } 374 | 375 | struct ubpf_func_proto ubpf_xdp_adjust_head_proto = { 376 | .func = (ext_func)ubpf_xdp_adjust_head, 377 | .arg_types = { 378 | XDP_MD_PTR, 379 | IMM, 380 | 0xff, 381 | 0xff, 382 | 0xff, 383 | }, 384 | .arg_sizes = { 385 | SIZE_PTR_MAX, 386 | SIZE_64, 387 | 0xff, 388 | 0xff, 389 | 0xff, 390 | }, 391 | .ret = UNKNOWN, 392 | }; 393 | 394 | uint64_t 395 | ubpf_xdp_adjust_head(void *xdp, uint64_t size) { 396 | int _size = (int) (size); 397 | struct xdp_md *_xdp = (struct xdp_md *)xdp; 398 | 399 | if (_size < -PKT_HEADROOM || _size > PKT_HEADROOM) { 400 | return -1; 401 | } else { 402 | _xdp->data += _size; 403 | return 0; 404 | } 405 | } 406 | 407 | struct ubpf_func_proto ubpf_xdp_adjust_tail_proto = { 408 | .func = (ext_func)ubpf_xdp_adjust_tail, 409 | .arg_types = { 410 | XDP_MD_PTR, 411 | IMM, 412 | 0xff, 413 | 0xff, 414 | 0xff, 415 | }, 416 | .arg_sizes = { 417 | SIZE_PTR_MAX, 418 | SIZE_64, 419 | 0xff, 420 | 0xff, 421 | 0xff, 422 | }, 423 | .ret = UNKNOWN, 424 | }; 425 | 426 | uint64_t 427 | ubpf_xdp_adjust_tail(void *xdp, uint64_t size) { 428 | int _size = (int) (size); 429 | struct xdp_md *_xdp = (struct xdp_md *)xdp; 430 | 431 | if (_size < -PKT_TAILROOM || _size > PKT_TAILROOM) { 432 | return -1; 433 | } else { 434 | _xdp->data_end += _size; 435 | return 0; 436 | } 437 | } 438 | 439 | struct ubpf_func_proto ubpf_redirect_map_proto = { 440 | .func = (ext_func)ubpf_redirect_map, 441 | .arg_types = { 442 | 0xff, 443 | 0xff, 444 | 0xff, 445 | 0xff, 446 | 0xff, 447 | }, 448 | .arg_sizes = { 449 | 0xff, 450 | 0xff, 451 | 0xff, 452 | 0xff, 453 | 0xff, 454 | }, 455 | .ret = UNKNOWN, 456 | }; 457 | 458 | uint64_t 459 | ubpf_redirect_map() { 460 | return 3; 461 | } 462 | 463 | void 464 | register_functions(struct ubpf_vm *vm) 465 | { 466 | ubpf_register_function(vm, MAP_LOOKUP, "ubpf_map_lookup", ubpf_map_lookup_proto); 467 | ubpf_register_function(vm, MAP_UPDATE, "ubpf_map_update", ubpf_map_update_proto); 468 | ubpf_register_function(vm, MAP_DELETE, "ubpf_map_delete", ubpf_map_delete_proto); 469 | ubpf_register_function(vm, MAP_ADD, "ubpf_map_add", ubpf_map_add_proto); 470 | ubpf_register_function(vm, TIME_GET_NS, "ubpf_time_get_ns", ubpf_time_get_ns_proto); 471 | ubpf_register_function(vm, HASH, "ubpf_hash", ubpf_hash_proto); 472 | ubpf_register_function(vm, GET_SMP_PROCESSOR_ID, "ubpf_get_smp_processor_id", ubpf_get_smp_processor_id_proto); 473 | ubpf_register_function(vm, CSUM_DIFF, "ubpf_csum_diff", ubpf_csum_diff_proto); 474 | ubpf_register_function(vm, XDP_ADJUST_HEAD, "ubpf_adjust_head", ubpf_xdp_adjust_head_proto); 475 | ubpf_register_function(vm, XDP_ADJUST_TAIL, "ubpf_adjust_tail", ubpf_xdp_adjust_tail_proto); 476 | ubpf_register_function(vm, REDIRECT_MAP, "ubpf_redirect_map", ubpf_redirect_map_proto); 477 | 478 | } 479 | -------------------------------------------------------------------------------- /ubpf/src/helper_functions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Axbryd 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 UBPF_HELPER_FUNCTIONS_H 18 | #define UBPF_HELPER_FUNCTIONS_H 19 | 20 | #include "ubpf.h" 21 | #include "ubpf_int.h" 22 | 23 | void * 24 | ubpf_map_lookup(const struct ubpf_map *map, void *key); 25 | 26 | int 27 | ubpf_map_update(struct ubpf_map *map, const void *key, void *item); 28 | 29 | int 30 | ubpf_map_add(struct ubpf_map *map, void *item); 31 | 32 | int 33 | ubpf_map_delete(struct ubpf_map *map, const void *key); 34 | 35 | uint64_t 36 | ubpf_time_get_ns(void); 37 | 38 | uint32_t 39 | ubpf_hash(void *item, uint64_t size); 40 | 41 | uint64_t 42 | ubpf_get_smp_processor_id(); 43 | 44 | //TODO: not implemented 45 | uint64_t 46 | ubpf_csum_diff(); 47 | 48 | uint64_t 49 | ubpf_xdp_adjust_head(void *xdp, uint64_t size); 50 | 51 | uint64_t 52 | ubpf_xdp_adjust_tail(void *xdp, uint64_t size); 53 | 54 | uint64_t 55 | ubpf_redirect_map(); 56 | 57 | void 58 | register_functions(struct ubpf_vm *vm); 59 | 60 | #endif //UBPF_HELPER_FUNCTIONS_H 61 | -------------------------------------------------------------------------------- /ubpf/src/helper_functions.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/helper_functions.o -------------------------------------------------------------------------------- /ubpf/src/inc/hmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016 Nicira, 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 HMAP_H 18 | #define HMAP_H 1 19 | 20 | #include 21 | #include 22 | #include "utils.h" 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* A hash map node, to be embedded inside the data structure being mapped. */ 29 | struct hmap_node { 30 | size_t hash; /* Hash value. */ 31 | struct hmap_node *next; /* Next in linked list. */ 32 | }; 33 | 34 | /* Returns the hash value embedded in 'node'. */ 35 | static inline size_t hmap_node_hash(const struct hmap_node *node) 36 | { 37 | return node->hash; 38 | } 39 | 40 | #define HMAP_NODE_NULL ((struct hmap_node *) 1) 41 | #define HMAP_NODE_NULL_INITIALIZER { 0, HMAP_NODE_NULL } 42 | 43 | /* Returns true if 'node' has been set to null by hmap_node_nullify() and has 44 | * not been un-nullified by being inserted into an hmap. */ 45 | static inline bool 46 | hmap_node_is_null(const struct hmap_node *node) 47 | { 48 | return node->next == HMAP_NODE_NULL; 49 | } 50 | 51 | /* Marks 'node' with a distinctive value that can be tested with 52 | * hmap_node_is_null(). */ 53 | static inline void 54 | hmap_node_nullify(struct hmap_node *node) 55 | { 56 | node->next = HMAP_NODE_NULL; 57 | } 58 | 59 | /* A hash map. */ 60 | struct hmap { 61 | struct hmap_node **buckets; /* Must point to 'one' iff 'mask' == 0. */ 62 | struct hmap_node *one; 63 | size_t mask; 64 | size_t n; 65 | }; 66 | 67 | /* Initializer for an empty hash map. */ 68 | #define HMAP_INITIALIZER(HMAP) \ 69 | { (struct hmap_node **const) &(HMAP)->one, NULL, 0, 0 } 70 | 71 | /* Initializer for an immutable struct hmap 'HMAP' that contains a single 72 | * 'NODE'. */ 73 | #define HMAP_CONST1(HMAP, NODE) { \ 74 | CONST_CAST(struct hmap_node **, &(HMAP)->one), NODE, 0, 1 } 75 | #define HMAP_NODE_INIT(HASH) { HASH, NULL } 76 | 77 | /* Initialization. */ 78 | void hmap_init(struct hmap *); 79 | void hmap_destroy(struct hmap *); 80 | void hmap_clear(struct hmap *); 81 | void hmap_swap(struct hmap *a, struct hmap *b); 82 | void hmap_moved(struct hmap *hmap); 83 | static inline size_t hmap_count(const struct hmap *); 84 | static inline bool hmap_is_empty(const struct hmap *); 85 | 86 | /* Adjusting capacity. */ 87 | void hmap_expand_at(struct hmap *, const char *where); 88 | #define hmap_expand(HMAP) hmap_expand_at(HMAP, OVS_SOURCE_LOCATOR) 89 | 90 | void hmap_shrink_at(struct hmap *, const char *where); 91 | #define hmap_shrink(HMAP) hmap_shrink_at(HMAP, OVS_SOURCE_LOCATOR) 92 | 93 | void hmap_reserve_at(struct hmap *, size_t capacity, const char *where); 94 | #define hmap_reserve(HMAP, CAPACITY) \ 95 | hmap_reserve_at(HMAP, CAPACITY, OVS_SOURCE_LOCATOR) 96 | 97 | /* Insertion and deletion. */ 98 | static inline void hmap_insert_at(struct hmap *, struct hmap_node *, 99 | size_t hash, const char *where); 100 | #define hmap_insert(HMAP, NODE, HASH) \ 101 | hmap_insert_at(HMAP, NODE, HASH, OVS_SOURCE_LOCATOR) 102 | 103 | static inline void hmap_insert_fast(struct hmap *, 104 | struct hmap_node *, size_t hash); 105 | static inline void hmap_remove(struct hmap *, struct hmap_node *); 106 | 107 | void hmap_node_moved(struct hmap *, struct hmap_node *, struct hmap_node *); 108 | static inline void hmap_replace(struct hmap *, const struct hmap_node *old, 109 | struct hmap_node *new_node); 110 | 111 | struct hmap_node *hmap_random_node(const struct hmap *); 112 | 113 | /* Search. 114 | * 115 | * HMAP_FOR_EACH_WITH_HASH iterates NODE over all of the nodes in HMAP that 116 | * have hash value equal to HASH. HMAP_FOR_EACH_IN_BUCKET iterates NODE over 117 | * all of the nodes in HMAP that would fall in the same bucket as HASH. MEMBER 118 | * must be the name of the 'struct hmap_node' member within NODE. 119 | * 120 | * These macros may be used interchangeably to search for a particular value in 121 | * an hmap, see, e.g. shash_find() for an example. Usually, using 122 | * HMAP_FOR_EACH_WITH_HASH provides an optimization, because comparing a hash 123 | * value is usually cheaper than comparing an entire hash map key. But for 124 | * simple hash map keys, it makes sense to use HMAP_FOR_EACH_IN_BUCKET because 125 | * it avoids doing two comparisons when a single simple comparison suffices. 126 | * 127 | * The loop should not change NODE to point to a different node or insert or 128 | * delete nodes in HMAP (unless it "break"s out of the loop to terminate 129 | * iteration). 130 | * 131 | * HASH is only evaluated once. 132 | * 133 | * When the loop terminates normally, meaning the iteration has completed 134 | * without using 'break', NODE will be NULL. This is true for all of the 135 | * HMAP_FOR_EACH_*() macros. 136 | */ 137 | #define HMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HMAP) \ 138 | for (INIT_CONTAINER(NODE, hmap_first_with_hash(HMAP, HASH), MEMBER); \ 139 | (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL); \ 140 | ASSIGN_CONTAINER(NODE, hmap_next_with_hash(&(NODE)->MEMBER), \ 141 | MEMBER)) 142 | #define HMAP_FOR_EACH_IN_BUCKET(NODE, MEMBER, HASH, HMAP) \ 143 | for (INIT_CONTAINER(NODE, hmap_first_in_bucket(HMAP, HASH), MEMBER); \ 144 | (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL); \ 145 | ASSIGN_CONTAINER(NODE, hmap_next_in_bucket(&(NODE)->MEMBER), MEMBER)) 146 | 147 | static inline struct hmap_node *hmap_first_with_hash(const struct hmap *, 148 | size_t hash); 149 | static inline struct hmap_node *hmap_next_with_hash(const struct hmap_node *); 150 | static inline struct hmap_node *hmap_first_in_bucket(const struct hmap *, 151 | size_t hash); 152 | static inline struct hmap_node *hmap_next_in_bucket(const struct hmap_node *); 153 | 154 | bool hmap_contains(const struct hmap *, const struct hmap_node *); 155 | 156 | /* Iteration. 157 | * 158 | * The *_INIT variants of these macros additionally evaluate the expressions 159 | * supplied following the HMAP argument once during the loop initialization. 160 | * This makes it possible for data structures that wrap around hmaps to insert 161 | * additional initialization into their iteration macros without having to 162 | * completely rewrite them. In particular, it can be a good idea to insert 163 | * BUILD_ASSERT_TYPE checks for map and node types that wrap hmap, since 164 | * otherwise it is possible for clients to accidentally confuse two derived 165 | * data structures that happen to use the same member names for struct hmap and 166 | * struct hmap_node. */ 167 | 168 | /* Iterates through every node in HMAP. */ 169 | #define HMAP_FOR_EACH(NODE, MEMBER, HMAP) \ 170 | HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, (void) 0) 171 | #define HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, ...) \ 172 | for (INIT_CONTAINER(NODE, hmap_first(HMAP), MEMBER), __VA_ARGS__; \ 173 | (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL); \ 174 | ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER)) 175 | 176 | /* Safe when NODE may be freed (not needed when NODE may be removed from the 177 | * hash map but its members remain accessible and intact). */ 178 | #define HMAP_FOR_EACH_SAFE(NODE, NEXT, MEMBER, HMAP) \ 179 | HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, (void) 0) 180 | #define HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, ...) \ 181 | for (INIT_CONTAINER(NODE, hmap_first(HMAP), MEMBER), __VA_ARGS__; \ 182 | ((NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL) \ 183 | ? INIT_CONTAINER(NEXT, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER), 1 \ 184 | : 0); \ 185 | (NODE) = (NEXT)) 186 | 187 | /* Continues an iteration from just after NODE. */ 188 | #define HMAP_FOR_EACH_CONTINUE(NODE, MEMBER, HMAP) \ 189 | HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, (void) 0) 190 | #define HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, ...) \ 191 | for (ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER), \ 192 | __VA_ARGS__; \ 193 | (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL); \ 194 | ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER)) 195 | 196 | static inline struct hmap_node * 197 | hmap_pop_helper__(struct hmap *hmap, size_t *bucket) { 198 | 199 | for (; *bucket <= hmap->mask; (*bucket)++) { 200 | struct hmap_node *node = hmap->buckets[*bucket]; 201 | 202 | if (node) { 203 | hmap_remove(hmap, node); 204 | return node; 205 | } 206 | } 207 | 208 | return NULL; 209 | } 210 | 211 | #define HMAP_FOR_EACH_POP(NODE, MEMBER, HMAP) \ 212 | for (size_t bucket__ = 0; \ 213 | INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \ 214 | (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL);) 215 | 216 | static inline struct hmap_node *hmap_first(const struct hmap *); 217 | static inline struct hmap_node *hmap_next(const struct hmap *, 218 | const struct hmap_node *); 219 | 220 | struct hmap_position { 221 | unsigned int bucket; 222 | unsigned int offset; 223 | }; 224 | 225 | struct hmap_node *hmap_at_position(const struct hmap *, 226 | struct hmap_position *); 227 | 228 | /* Returns the number of nodes currently in 'hmap'. */ 229 | static inline size_t 230 | hmap_count(const struct hmap *hmap) 231 | { 232 | return hmap->n; 233 | } 234 | 235 | /* Returns the maximum number of nodes that 'hmap' may hold before it should be 236 | * rehashed. */ 237 | static inline size_t 238 | hmap_capacity(const struct hmap *hmap) 239 | { 240 | return hmap->mask * 2 + 1; 241 | } 242 | 243 | /* Returns true if 'hmap' currently contains no nodes, 244 | * false otherwise. 245 | * Note: While hmap in general is not thread-safe without additional locking, 246 | * hmap_is_empty() is. */ 247 | static inline bool 248 | hmap_is_empty(const struct hmap *hmap) 249 | { 250 | return hmap->n == 0; 251 | } 252 | 253 | /* Inserts 'node', with the given 'hash', into 'hmap'. 'hmap' is never 254 | * expanded automatically. */ 255 | static inline void 256 | hmap_insert_fast(struct hmap *hmap, struct hmap_node *node, size_t hash) 257 | { 258 | struct hmap_node **bucket = &hmap->buckets[hash & hmap->mask]; 259 | node->hash = hash; 260 | node->next = *bucket; 261 | *bucket = node; 262 | hmap->n++; 263 | } 264 | 265 | /* Inserts 'node', with the given 'hash', into 'hmap', and expands 'hmap' if 266 | * necessary to optimize search performance. 267 | * 268 | * ('where' is used in debug logging. Commonly one would use hmap_insert() to 269 | * automatically provide the caller's source file and line number for 270 | * 'where'.) */ 271 | static inline void 272 | hmap_insert_at(struct hmap *hmap, struct hmap_node *node, size_t hash, 273 | const char *where) 274 | { 275 | hmap_insert_fast(hmap, node, hash); 276 | if (hmap->n / 2 > hmap->mask) { 277 | hmap_expand_at(hmap, where); 278 | } 279 | } 280 | 281 | /* Removes 'node' from 'hmap'. Does not shrink the hash table; call 282 | * hmap_shrink() directly if desired. */ 283 | static inline void 284 | hmap_remove(struct hmap *hmap, struct hmap_node *node) 285 | { 286 | struct hmap_node **bucket = &hmap->buckets[node->hash & hmap->mask]; 287 | while (*bucket != node) { 288 | bucket = &(*bucket)->next; 289 | } 290 | *bucket = node->next; 291 | hmap->n--; 292 | } 293 | 294 | /* Puts 'new_node' in the position in 'hmap' currently occupied by 'old_node'. 295 | * The 'new_node' must hash to the same value as 'old_node'. The client is 296 | * responsible for ensuring that the replacement does not violate any 297 | * client-imposed invariants (e.g. uniqueness of keys within a map). 298 | * 299 | * Afterward, 'old_node' is not part of 'hmap', and the client is responsible 300 | * for freeing it (if this is desirable). */ 301 | static inline void 302 | hmap_replace(struct hmap *hmap, 303 | const struct hmap_node *old_node, struct hmap_node *new_node) 304 | { 305 | struct hmap_node **bucket = &hmap->buckets[old_node->hash & hmap->mask]; 306 | while (*bucket != old_node) { 307 | bucket = &(*bucket)->next; 308 | } 309 | *bucket = new_node; 310 | new_node->hash = old_node->hash; 311 | new_node->next = old_node->next; 312 | } 313 | 314 | static inline struct hmap_node * 315 | hmap_next_with_hash__(const struct hmap_node *node, size_t hash) 316 | { 317 | while (node != NULL && node->hash != hash) { 318 | node = node->next; 319 | } 320 | return CONST_CAST(struct hmap_node *, node); 321 | } 322 | 323 | /* Returns the first node in 'hmap' with the given 'hash', or a null pointer if 324 | * no nodes have that hash value. */ 325 | static inline struct hmap_node * 326 | hmap_first_with_hash(const struct hmap *hmap, size_t hash) 327 | { 328 | return hmap_next_with_hash__(hmap->buckets[hash & hmap->mask], hash); 329 | } 330 | 331 | /* Returns the first node in 'hmap' in the bucket in which the given 'hash' 332 | * would land, or a null pointer if that bucket is empty. */ 333 | static inline struct hmap_node * 334 | hmap_first_in_bucket(const struct hmap *hmap, size_t hash) 335 | { 336 | return hmap->buckets[hash & hmap->mask]; 337 | } 338 | 339 | /* Returns the next node in the same bucket as 'node', or a null pointer if 340 | * there are no more nodes in that bucket. 341 | * 342 | * If the hash map has been reallocated since 'node' was visited, some nodes 343 | * may be skipped; if new nodes with the same hash value have been added, they 344 | * will be skipped. (Removing 'node' from the hash map does not prevent 345 | * calling this function, since node->next is preserved, although freeing 346 | * 'node' of course does.) */ 347 | static inline struct hmap_node * 348 | hmap_next_in_bucket(const struct hmap_node *node) 349 | { 350 | return node->next; 351 | } 352 | 353 | /* Returns the next node in the same hash map as 'node' with the same hash 354 | * value, or a null pointer if no more nodes have that hash value. 355 | * 356 | * If the hash map has been reallocated since 'node' was visited, some nodes 357 | * may be skipped; if new nodes with the same hash value have been added, they 358 | * will be skipped. (Removing 'node' from the hash map does not prevent 359 | * calling this function, since node->next is preserved, although freeing 360 | * 'node' of course does.) */ 361 | static inline struct hmap_node * 362 | hmap_next_with_hash(const struct hmap_node *node) 363 | { 364 | return hmap_next_with_hash__(node->next, node->hash); 365 | } 366 | 367 | static inline struct hmap_node * 368 | hmap_next__(const struct hmap *hmap, size_t start) 369 | { 370 | size_t i; 371 | for (i = start; i <= hmap->mask; i++) { 372 | struct hmap_node *node = hmap->buckets[i]; 373 | if (node) { 374 | return node; 375 | } 376 | } 377 | return NULL; 378 | } 379 | 380 | /* Returns the first node in 'hmap', in arbitrary order, or a null pointer if 381 | * 'hmap' is empty. */ 382 | static inline struct hmap_node * 383 | hmap_first(const struct hmap *hmap) 384 | { 385 | return hmap_next__(hmap, 0); 386 | } 387 | 388 | /* Returns the next node in 'hmap' following 'node', in arbitrary order, or a 389 | * null pointer if 'node' is the last node in 'hmap'. 390 | * 391 | * If the hash map has been reallocated since 'node' was visited, some nodes 392 | * may be skipped or visited twice. (Removing 'node' from the hash map does 393 | * not prevent calling this function, since node->next is preserved, although 394 | * freeing 'node' of course does.) */ 395 | static inline struct hmap_node * 396 | hmap_next(const struct hmap *hmap, const struct hmap_node *node) 397 | { 398 | return (node->next 399 | ? node->next 400 | : hmap_next__(hmap, (node->hash & hmap->mask) + 1)); 401 | } 402 | 403 | #ifdef __cplusplus 404 | } 405 | #endif 406 | 407 | #endif /* hmap.h */ 408 | -------------------------------------------------------------------------------- /ubpf/src/inc/sclog4c.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 - 2015 Christian Hujer. 2 | * All rights reserved. 3 | * Licensed under LGPLv3. 4 | * See file LICENSE in the root directory of this project. 5 | */ 6 | 7 | #ifndef SCLOG4C_H 8 | #define SCLOG4C_H 9 | 10 | #include 11 | #include 12 | 13 | /** The predefined log levels. */ 14 | enum LogLevel { 15 | SL4C_ALL = INT_MIN, 16 | SL4C_FINEST = 300, 17 | SL4C_FINER = 400, 18 | SL4C_FINE = 500, 19 | SL4C_DEBUG = 600, 20 | SL4C_CONFIG = 700, 21 | SL4C_INFO = 800, 22 | SL4C_WARNING = 900, 23 | SL4C_ERROR = 950, 24 | SL4C_SEVERE = 1000, 25 | SL4C_FATAL = 1100, 26 | SL4C_OFF = INT_MAX 27 | }; 28 | 29 | #if !defined(SCLOG4C_LEVEL) || defined(_doxygen) 30 | /** The global log level for compile-time log decision. */ 31 | #define SCLOG4C_LEVEL SL4C_ALL 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | /** The global log level. */ 39 | extern int sclog4c_level; 40 | 41 | /** Returns a textual description of the specified @p level. 42 | * @param level 43 | * Level for which to return a textual description. 44 | * @return String describing @p level. 45 | */ 46 | extern const char *describe(int level); 47 | 48 | /** Prints a formatted log message to stderr. 49 | * @param level 50 | * Level for which the log message is to be generated. 51 | * Note this should not be an expression with side effects because the macro might evaluate this more than once. 52 | * @param fmt 53 | * Format string for the log message. 54 | * This must be a string literal. 55 | * @param ... 56 | * Format arguments. 57 | */ 58 | #if defined(_doxygen) || defined(__GNUC__) || defined(__CC_ARM) 59 | #define logm(level, fmt, ...) \ 60 | if (level >= SCLOG4C_LEVEL) do { \ 61 | if (level >= sclog4c_level) \ 62 | fprintf(stderr, "%s:%d: %s: In function %s: " fmt "\n", __FILE__, __LINE__, describe(level), __func__, ##__VA_ARGS__); \ 63 | } while (0) 64 | #elif defined(__MSC_VER) && (__MSC_VER >= 1400) 65 | #define logm(level, fmt, ...) \ 66 | if (level >= SCLOG4C_LEVEL) do { \ 67 | if (level >= sclog4c_level) \ 68 | fprintf(stderr, "%s:%d: %s: In function %s: " fmt "\n", __FILE__, __LINE__, describe(level), __FUNCTION__, __VA_ARGS__); \ 69 | } while (0) 70 | #elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) 71 | #define logm(level, ...) \ 72 | if (level >= SCLOG4C_LEVEL) do { \ 73 | if (level >= sclog4c_level) { \ 74 | fprintf(stderr, "%s:%d: %s: In function %s: ", __FILE__, __LINE__, describe(level), __func__); \ 75 | fprintf(stderr, __VA_ARGS__); \ 76 | fprintf(stderr, "\n"); \ 77 | } \ 78 | } while (0) 79 | #else 80 | #define logm(level, ...) \ 81 | if (level >= SCLOG4C_LEVEL) do { \ 82 | if (level >= sclog4c_level) { \ 83 | fprintf(stderr, "%s:%d: %s: ", __FILE__, __LINE__, describe(level)); \ 84 | fprintf(stderr, __VA_ARGS__); \ 85 | fprintf(stderr, "\n"); \ 86 | } \ 87 | } while (0) 88 | #endif 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /ubpf/src/inc/ubpf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Big Switch Networks, Inc 3 | * Copyright 2022 Axbryd 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef UBPF_H 19 | #define UBPF_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "../match_unit.h" 26 | 27 | struct ubpf_vm; 28 | struct ubpf_map; 29 | struct ubpf_func_proto; 30 | 31 | typedef uint64_t (*ubpf_jit_fn)(void *mem, size_t mem_len); 32 | 33 | struct ubpf_vm *ubpf_create(void); 34 | void ubpf_destroy(struct ubpf_vm *vm); 35 | 36 | struct xdp_md { 37 | uintptr_t data; 38 | uintptr_t data_end; 39 | }; 40 | 41 | struct map_context { 42 | uint16_t pc; 43 | uint64_t *reg; 44 | uint64_t *stack; 45 | uint64_t *old_reg; 46 | uint64_t *old_stack; 47 | }; 48 | 49 | /* 50 | * Enable / disable bounds_check 51 | * 52 | * Bounds check is enabled by default, but it may be too restrictive 53 | * Pass true to enable, false to disable 54 | * Returns previous state 55 | */ 56 | bool toggle_bounds_check(struct ubpf_vm *vm, bool enable); 57 | 58 | /* 59 | * Register an external function 60 | * 61 | * The immediate field of a CALL instruction is an index into an array of 62 | * functions registered by the user. This API associates a function with 63 | * an index. 64 | * 65 | * 'name' should be a string with a lifetime longer than the VM. 66 | * 67 | * Returns 0 on success, -1 on error. 68 | */ 69 | int ubpf_register_function(struct ubpf_vm *vm, unsigned int idx, const char *name, struct ubpf_func_proto proto); 70 | 71 | /* 72 | * Register an external variable. 73 | * 74 | * 'name' should be a string with a lifetime longer than the VM. 75 | * 76 | * Returns 0 on success, -1 on error. 77 | */ 78 | int ubpf_register_map(struct ubpf_vm *vm, const char *name, struct ubpf_map *map); 79 | 80 | /* 81 | * Load code into a VM 82 | * 83 | * This must be done before calling ubpf_exec or ubpf_compile and after 84 | * registering all functions. 85 | * 86 | * 'code' should point to eBPF bytecodes and 'code_len' should be the size in 87 | * bytes of that buffer. 88 | * 89 | * Returns 0 on success, -1 on error. In case of error a pointer to the error 90 | * message will be stored in 'errmsg' and should be freed by the caller. 91 | */ 92 | int ubpf_load(struct ubpf_vm *vm, const void *code, uint32_t code_len, char **errmsg); 93 | 94 | /* 95 | * Load code from an ELF file 96 | * 97 | * This must be done before calling ubpf_exec or ubpf_compile and after 98 | * registering all functions. 99 | * 100 | * 'elf' should point to a copy of an ELF file in memory and 'elf_len' should 101 | * be the size in bytes of that buffer. 102 | * 103 | * The ELF file must be 64-bit little-endian with a single text section 104 | * containing the eBPF bytecodes. This is compatible with the output of 105 | * Clang. 106 | * 107 | * Returns 0 on success, -1 on error. In case of error a pointer to the error 108 | * message will be stored in 'errmsg' and should be freed by the caller. 109 | */ 110 | int ubpf_load_elf(struct ubpf_vm *vm, const void *elf, size_t elf_len, char **errmsg); 111 | 112 | uint64_t ubpf_exec(const struct ubpf_vm *vm, struct xdp_md *xdp, 113 | struct reg_def *regs_def, struct stack_def *stack, 114 | uint16_t pc_start, uint8_t map_id); 115 | 116 | ubpf_jit_fn ubpf_compile(struct ubpf_vm *vm, char **errmsg); 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /ubpf/src/inc/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, 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 OPENVSWITCH_UTIL_H 18 | #define OPENVSWITCH_UTIL_H 1 19 | 20 | #include 21 | #include 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /* This is a void expression that issues a compiler error if POINTER cannot be 28 | * compared for equality with the given pointer TYPE. This generally means 29 | * that POINTER is a qualified or unqualified TYPE. However, 30 | * BUILD_ASSERT_TYPE(POINTER, void *) will accept any pointer to object type, 31 | * because any pointer to object can be compared for equality with "void *". 32 | * 33 | * POINTER can be any expression. The use of "sizeof" ensures that the 34 | * expression is not actually evaluated, so that any side effects of the 35 | * expression do not occur. 36 | * 37 | * The cast to int is present only to suppress an "expression using sizeof 38 | * bool" warning from "sparse" (see 39 | * http://permalink.gmane.org/gmane.comp.parsers.sparse/2967). */ 40 | #define BUILD_ASSERT_TYPE(POINTER, TYPE) \ 41 | ((void) sizeof ((int) ((POINTER) == (TYPE) (POINTER)))) 42 | 43 | /* Casts 'pointer' to 'type' and issues a compiler warning if the cast changes 44 | * anything other than an outermost "const" or "volatile" qualifier. 45 | * 46 | * The cast to int is present only to suppress an "expression using sizeof 47 | * bool" warning from "sparse" (see 48 | * http://permalink.gmane.org/gmane.comp.parsers.sparse/2967). */ 49 | #define CONST_CAST(TYPE, POINTER) \ 50 | (BUILD_ASSERT_TYPE(POINTER, TYPE), \ 51 | (TYPE) (POINTER)) 52 | 53 | /* Given a pointer-typed lvalue OBJECT, expands to a pointer type that may be 54 | * assigned to OBJECT. */ 55 | #ifdef __GNUC__ 56 | #define OVS_TYPEOF(OBJECT) typeof(OBJECT) 57 | #else 58 | #define OVS_TYPEOF(OBJECT) void * 59 | #endif 60 | 61 | /* Given OBJECT of type pointer-to-structure, expands to the offset of MEMBER 62 | * within an instance of the structure. 63 | * 64 | * The GCC-specific version avoids the technicality of undefined behavior if 65 | * OBJECT is null, invalid, or not yet initialized. This makes some static 66 | * checkers (like Coverity) happier. But the non-GCC version does not actually 67 | * dereference any pointer, so it would be surprising for it to cause any 68 | * problems in practice. 69 | */ 70 | #ifdef __GNUC__ 71 | #define OBJECT_OFFSETOF(OBJECT, MEMBER) offsetof(typeof(*(OBJECT)), MEMBER) 72 | #else 73 | #define OBJECT_OFFSETOF(OBJECT, MEMBER) \ 74 | ((char *) &(OBJECT)->MEMBER - (char *) (OBJECT)) 75 | #endif 76 | 77 | /* Yields the size of MEMBER within STRUCT. */ 78 | #define MEMBER_SIZEOF(STRUCT, MEMBER) (sizeof(((STRUCT *) NULL)->MEMBER)) 79 | 80 | /* Yields the offset of the end of MEMBER within STRUCT. */ 81 | #define OFFSETOFEND(STRUCT, MEMBER) \ 82 | (offsetof(STRUCT, MEMBER) + MEMBER_SIZEOF(STRUCT, MEMBER)) 83 | 84 | /* Given POINTER, the address of the given MEMBER in a STRUCT object, returns 85 | the STRUCT object. */ 86 | #define CONTAINER_OF(POINTER, STRUCT, MEMBER) \ 87 | ((STRUCT *) (void *) ((char *) (POINTER) - offsetof (STRUCT, MEMBER))) 88 | 89 | /* Given POINTER, the address of the given MEMBER within an object of the type 90 | * that that OBJECT points to, returns OBJECT as an assignment-compatible 91 | * pointer type (either the correct pointer type or "void *"). OBJECT must be 92 | * an lvalue. 93 | * 94 | * This is the same as CONTAINER_OF except that it infers the structure type 95 | * from the type of '*OBJECT'. */ 96 | #define OBJECT_CONTAINING(POINTER, OBJECT, MEMBER) \ 97 | ((OVS_TYPEOF(OBJECT)) (void *) \ 98 | ((char *) (POINTER) - OBJECT_OFFSETOF(OBJECT, MEMBER))) 99 | 100 | /* Given POINTER, the address of the given MEMBER within an object of the type 101 | * that that OBJECT points to, assigns the address of the outer object to 102 | * OBJECT, which must be an lvalue. 103 | * 104 | * Evaluates to (void) 0 as the result is not to be used. */ 105 | #define ASSIGN_CONTAINER(OBJECT, POINTER, MEMBER) \ 106 | ((OBJECT) = OBJECT_CONTAINING(POINTER, OBJECT, MEMBER), (void) 0) 107 | 108 | /* As explained in the comment above OBJECT_OFFSETOF(), non-GNUC compilers 109 | * like MSVC will complain about un-initialized variables if OBJECT 110 | * hasn't already been initialized. To prevent such warnings, INIT_CONTAINER() 111 | * can be used as a wrapper around ASSIGN_CONTAINER. */ 112 | #define INIT_CONTAINER(OBJECT, POINTER, MEMBER) \ 113 | ((OBJECT) = NULL, ASSIGN_CONTAINER(OBJECT, POINTER, MEMBER)) 114 | 115 | /* Returns the number of elements in ARRAY. */ 116 | #define ARRAY_SIZE(ARRAY) __ARRAY_SIZE(ARRAY) 117 | 118 | /* Returns X / Y, rounding up. X must be nonnegative to round correctly. */ 119 | #define DIV_ROUND_UP(X, Y) (((X) + ((Y) - 1)) / (Y)) 120 | 121 | /* Returns X rounded up to the nearest multiple of Y. */ 122 | #define ROUND_UP(X, Y) (DIV_ROUND_UP(X, Y) * (Y)) 123 | 124 | /* Returns the least number that, when added to X, yields a multiple of Y. */ 125 | #define PAD_SIZE(X, Y) (ROUND_UP(X, Y) - (X)) 126 | 127 | /* Returns X rounded down to the nearest multiple of Y. */ 128 | #define ROUND_DOWN(X, Y) ((X) / (Y) * (Y)) 129 | 130 | /* Returns true if X is a power of 2, otherwise false. */ 131 | #define IS_POW2(X) ((X) && !((X) & ((X) - 1))) 132 | 133 | static inline bool 134 | is_pow2(uintmax_t x) 135 | { 136 | return IS_POW2(x); 137 | } 138 | 139 | /* Returns X rounded up to a power of 2. X must be a constant expression. */ 140 | #define ROUND_UP_POW2(X) RUP2__(X) 141 | #define RUP2__(X) (RUP2_1(X) + 1) 142 | #define RUP2_1(X) (RUP2_2(X) | (RUP2_2(X) >> 16)) 143 | #define RUP2_2(X) (RUP2_3(X) | (RUP2_3(X) >> 8)) 144 | #define RUP2_3(X) (RUP2_4(X) | (RUP2_4(X) >> 4)) 145 | #define RUP2_4(X) (RUP2_5(X) | (RUP2_5(X) >> 2)) 146 | #define RUP2_5(X) (RUP2_6(X) | (RUP2_6(X) >> 1)) 147 | #define RUP2_6(X) ((X) - 1) 148 | 149 | /* Returns X rounded down to a power of 2. X must be a constant expression. */ 150 | #define ROUND_DOWN_POW2(X) RDP2__(X) 151 | #define RDP2__(X) (RDP2_1(X) - (RDP2_1(X) >> 1)) 152 | #define RDP2_1(X) (RDP2_2(X) | (RDP2_2(X) >> 16)) 153 | #define RDP2_2(X) (RDP2_3(X) | (RDP2_3(X) >> 8)) 154 | #define RDP2_3(X) (RDP2_4(X) | (RDP2_4(X) >> 4)) 155 | #define RDP2_4(X) (RDP2_5(X) | (RDP2_5(X) >> 2)) 156 | #define RDP2_5(X) ( (X) | ( (X) >> 1)) 157 | 158 | /* Macros for sizing bitmaps */ 159 | #define BITMAP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT) 160 | #define BITMAP_N_LONGS(N_BITS) DIV_ROUND_UP(N_BITS, BITMAP_ULONG_BITS) 161 | 162 | /* Given ATTR, and TYPE, cast the ATTR to TYPE by first casting ATTR to 163 | * (void *). This is to suppress the alignment warning issued by clang. */ 164 | #define ALIGNED_CAST(TYPE, ATTR) ((TYPE) (void *) (ATTR)) 165 | 166 | #ifdef __cplusplus 167 | } 168 | #endif 169 | 170 | #endif 171 | 172 | -------------------------------------------------------------------------------- /ubpf/src/libubpf.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/libubpf.a -------------------------------------------------------------------------------- /ubpf/src/lookup3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Orange 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 | #ifndef LOOKUP3_H 17 | #define LOOKUP3_H 18 | 19 | #include /* defines printf for tests */ 20 | #include /* defines time_t for timings in the test */ 21 | #include /* defines uint32_t etc */ 22 | #include /* attempt to define endianness */ 23 | #ifdef linux 24 | # include /* attempt to define endianness */ 25 | #endif 26 | 27 | uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval); 28 | void hashword2(const uint32_t *k, size_t length, uint32_t *pc, uint32_t *pb); 29 | uint32_t hashlittle( const void *key, size_t length, uint32_t initval); 30 | uint32_t hashbig( const void *key, size_t length, uint32_t initval); 31 | void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ubpf/src/lookup3.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/lookup3.o -------------------------------------------------------------------------------- /ubpf/src/match_unit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Axbryd 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 UBPF_MATCH_UNIT_H 18 | #define UBPF_MATCH_UNIT_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include "cJSON.h" 24 | 25 | #define round_up_to_8(x) ((x+7) & (-8)) 26 | #define MAX_OPS 8 27 | 28 | enum alu_ops { 29 | ALU_OPS_NULL, 30 | ALU_OPS_LE, 31 | ALU_OPS_BE, 32 | ALU_OPS_AND, 33 | ALU_OPS_OR, 34 | ALU_OPS_LSH, 35 | ALU_OPS_RSH, 36 | ALU_OPS_ADD, 37 | }; 38 | 39 | enum reg_def_ops { 40 | REG_DEF_NULL, 41 | REG_DEF_IMM, 42 | REG_DEF_STACK_PTR, 43 | REG_DEF_PKT_PTR, 44 | REG_DEF_PKT_FLD, 45 | REG_DEF_PKT_END, 46 | REG_DEF_CTX_PTR, 47 | }; 48 | 49 | struct pkt_field_def { 50 | uint16_t offset; // in bytes 51 | uint8_t len; // in bits 52 | enum alu_ops op[MAX_OPS]; 53 | uint8_t nb_ops; 54 | uint64_t imm[MAX_OPS]; 55 | }; 56 | 57 | struct pkt_field { 58 | void *value; 59 | bool dontcare; 60 | }; 61 | 62 | enum action_ops { 63 | XDP_ABORTED = 0, 64 | XDP_DROP, 65 | XDP_PASS, 66 | XDP_TX, 67 | XDP_REDIRECT, 68 | MAP_ACCESS, 69 | ABANDON 70 | }; 71 | 72 | struct key_field { 73 | int kstart; 74 | int kend; 75 | uint64_t imm; 76 | bool has_imm; 77 | enum reg_def_ops type; 78 | struct pkt_field_def pkt_fld; 79 | }; 80 | 81 | struct reg_def { 82 | uint64_t val; 83 | int offset; 84 | uint8_t len; 85 | enum reg_def_ops type; 86 | struct pkt_field_def pkt_fld; 87 | }; 88 | 89 | struct stack_def { 90 | uint8_t nb_fields; 91 | struct key_field *key_fields; 92 | }; 93 | 94 | struct action_entry { 95 | enum action_ops op; 96 | uint8_t map_id; 97 | uint16_t pc; 98 | struct reg_def reg_def[11]; 99 | struct stack_def stack_def; 100 | }; 101 | 102 | struct match_entry { 103 | struct pkt_field *fields; 104 | struct action_entry *act; 105 | uint8_t nb_pkt_fields; 106 | uint64_t cnt; 107 | }; 108 | 109 | struct match_table { 110 | struct match_entry *entries; 111 | uint8_t nb_entries; 112 | struct pkt_field_def *field_defs; 113 | }; 114 | 115 | struct action_entry * 116 | lookup_entry(struct match_table *mat, struct pkt_field *parsed_fields); 117 | 118 | int 119 | parse_mat_json(const char *jstring, size_t buf_len, struct match_table *mat); 120 | 121 | struct pkt_field * 122 | parse_pkt_header(const u_char *pkt, struct match_table *mat); 123 | 124 | void 125 | dump_fields(struct pkt_field *parsed_fields, uint8_t nb_fields); 126 | 127 | //u_char * 128 | //generate_key(struct action_entry *act, const u_char *pkt, size_t *key_len); 129 | 130 | int 131 | parse_context(struct action_entry *act, const cJSON *context); 132 | 133 | uint64_t 134 | field_manipulation(enum alu_ops op, uint64_t imm, 135 | uint64_t value, uint8_t fld_len_in_bytes); 136 | 137 | 138 | #endif //UBPF_MATCH_UNIT_H 139 | -------------------------------------------------------------------------------- /ubpf/src/match_unit.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/match_unit.o -------------------------------------------------------------------------------- /ubpf/src/sclog4c.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2014 Christian Hujer. 2 | * All rights reserved. 3 | * Licensed under LGPLv3. 4 | * See file LICENSE in the root directory of this project. 5 | */ 6 | 7 | #include "inc/sclog4c.h" 8 | 9 | int sclog4c_level = SL4C_WARNING; 10 | 11 | static const struct sclog4c_messages { 12 | int level; 13 | const char *message; 14 | } sclog4c_messages[] = { 15 | { SL4C_FATAL, "fatal" }, 16 | { SL4C_SEVERE, "severe" }, 17 | { SL4C_ERROR, "error" }, 18 | { SL4C_WARNING, "warning" }, 19 | { SL4C_INFO, "info" }, 20 | { SL4C_CONFIG, "config" }, 21 | { SL4C_DEBUG, "debug" }, 22 | { SL4C_FINE, "fine" }, 23 | { SL4C_FINER, "finer" }, 24 | { SL4C_FINEST, "finest" }, 25 | }; 26 | 27 | const char *describe(int level) 28 | { 29 | size_t i; 30 | for (i = 0; i < sizeof(sclog4c_messages) / sizeof(sclog4c_messages[0]); i++) 31 | if (level >= sclog4c_messages[i].level) 32 | return sclog4c_messages[i].message; 33 | return "all"; 34 | } -------------------------------------------------------------------------------- /ubpf/src/sclog4c.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/sclog4c.o -------------------------------------------------------------------------------- /ubpf/src/ubpf_array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Orange 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 | #include 17 | #include 18 | #include 19 | #include 20 | #include "inttypes.h" 21 | 22 | //#include 23 | //#include "util.h" 24 | 25 | #include "ubpf_int.h" 26 | 27 | void *ubpf_array_create(const struct ubpf_map *map); 28 | static void *ubpf_array_lookup(const struct ubpf_map *map, const void *key); 29 | static int ubpf_array_update(struct ubpf_map *map, const void *key, 30 | void *value); 31 | 32 | static inline uint64_t 33 | log2u(uint64_t x) { 34 | uint64_t res = 0; 35 | 36 | while(x >>= 1) res++; 37 | 38 | return res; 39 | } 40 | 41 | const struct ubpf_map_ops ubpf_array_ops = { 42 | .map_lookup = ubpf_array_lookup, 43 | .map_update = ubpf_array_update, 44 | .map_delete = NULL, 45 | .map_add = NULL, 46 | }; 47 | 48 | void * 49 | ubpf_array_create(const struct ubpf_map *map) 50 | { 51 | return calloc(map->max_entries, map->value_size); 52 | } 53 | 54 | static void * 55 | ubpf_array_lookup(const struct ubpf_map *map, const void *key) 56 | { 57 | uint64_t mask = (1lu << (log2u(map->max_entries))) - 1lu; 58 | uintptr_t ret; 59 | 60 | uint64_t idx = *((const uint64_t *)key) & mask; 61 | if (idx >= map->max_entries) { 62 | logm(SL4C_ERROR, "Null, idx=%lx, mask=%lx, key_size=%u\n", idx, mask, map->key_size); 63 | return NULL; 64 | } 65 | if (map->type == UBPF_MAP_TYPE_ARRAY_OF_MAPS) 66 | ret = *(uintptr_t*)((uint64_t)map->data + idx * map->value_size); 67 | else 68 | return (void *)((uint64_t)map->data + idx * map->value_size); 69 | 70 | return (void *)(ret); 71 | } 72 | 73 | static int 74 | ubpf_array_update(struct ubpf_map *map, const void *key, void *value) 75 | { 76 | uint64_t idx = *((const uint64_t *)key); 77 | if (idx >= map->max_entries) { 78 | return -5; 79 | } 80 | void *addr = (void *)((uint64_t)map->data + map->value_size * idx); 81 | memcpy(addr, value, map->value_size); 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /ubpf/src/ubpf_array.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/ubpf_array.o -------------------------------------------------------------------------------- /ubpf/src/ubpf_hashmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Orange 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 | #include 17 | #include 18 | #include 19 | 20 | //#include 21 | #include "ubpf_hashmap.h" 22 | 23 | static inline void 24 | dl_list_init(struct dl_list *list) 25 | { 26 | list->next = list->prev = list; 27 | } 28 | 29 | void * 30 | ubpf_hashmap_create(const struct ubpf_map *map) 31 | { 32 | struct hashmap *hmap = malloc(sizeof(*hmap)); 33 | 34 | hmap->nb_buckets = round_up_pow_of_two(map->max_entries); 35 | hmap->count = 0; 36 | hmap->elem_size = sizeof(struct hmap_elem) + round_up(map->key_size, 8) 37 | + map->value_size; 38 | 39 | hmap->buckets = malloc(sizeof(struct dl_list) * hmap->nb_buckets); 40 | 41 | for (int i = 0; i < hmap->nb_buckets; i++) { 42 | dl_list_init(&hmap->buckets[i]); 43 | } 44 | 45 | return hmap; 46 | } 47 | 48 | static inline uint32_t ubpf_hashmap_hash(const void *key, uint32_t key_len) 49 | { 50 | return hashlittle(key, key_len, 0); 51 | } 52 | 53 | static inline struct dl_list *select_bucket(struct hashmap *hmap, 54 | uint32_t hash) 55 | { 56 | return &hmap->buckets[hash & (hmap->nb_buckets - 1)]; 57 | } 58 | 59 | static inline struct hmap_elem* lookup_elem_raw(struct dl_list *head, 60 | uint32_t hash, const void *key, 61 | uint32_t key_size) 62 | { 63 | struct hmap_elem *l; 64 | LIST_FOR_EACH(l, hash_node, head) { 65 | if (l == NULL) 66 | return NULL; 67 | if (l->hash == hash && !memcmp(&l->key, key, key_size)) { 68 | return l; 69 | } 70 | } 71 | return NULL; 72 | } 73 | 74 | unsigned int 75 | ubpf_hashmap_size(const struct ubpf_map *map) 76 | { 77 | struct hashmap *hmap = map->data; 78 | return hmap->count; 79 | } 80 | 81 | unsigned int 82 | ubpf_hashmap_dump(const struct ubpf_map *map, void *data) 83 | { 84 | struct hashmap *hmap = map->data; 85 | const struct dl_list *head; 86 | struct hmap_elem *element; 87 | int key_size = map->key_size; 88 | int value_size = map->value_size; 89 | int key_rounded_size = round_up(map->key_size, 8); 90 | 91 | for(int j = 0; j < hmap->nb_buckets; j++) { 92 | head = hmap->buckets + j; 93 | 94 | LIST_FOR_EACH(element, hash_node, head) { 95 | if (element != NULL) { 96 | void *key_pointer = element->key; 97 | memcpy(data, key_pointer, key_size); 98 | data += key_size; 99 | 100 | void *value_pointer = key_pointer + key_rounded_size; 101 | memcpy(data, value_pointer, value_size); 102 | data += value_size; 103 | } 104 | } 105 | } 106 | 107 | return hmap->count; 108 | } 109 | 110 | void * 111 | ubpf_hashmap_lookup(const struct ubpf_map *map, const void *key) 112 | { 113 | struct hmap_elem *elem; 114 | struct hashmap *hmap = map->data; 115 | 116 | uint32_t hash = ubpf_hashmap_hash(key, map->key_size); 117 | struct dl_list *head = select_bucket(hmap, hash); 118 | elem = lookup_elem_raw(head, hash, key, map->key_size); 119 | 120 | if (elem) { 121 | return elem->key + round_up(map->key_size, 8); 122 | } 123 | return NULL; 124 | } 125 | 126 | int 127 | ubpf_hashmap_update(struct ubpf_map *map, const void *key, void *value) 128 | { 129 | struct hmap_elem *old_elem; 130 | struct hashmap *hmap = map->data; 131 | 132 | uint32_t hash = ubpf_hashmap_hash(key, map->key_size); 133 | struct dl_list *head = select_bucket(hmap, hash); 134 | old_elem = lookup_elem_raw(head, hash, key, map->key_size); 135 | 136 | if (!old_elem && (hmap->count >= map->max_entries)) { 137 | return -4; 138 | } 139 | 140 | struct hmap_elem *new_elem = malloc(hmap->elem_size); 141 | new_elem->hash = hash; 142 | memcpy(new_elem->key, key, map->key_size); 143 | void *value_ptr = new_elem->key + round_up(map->key_size, 8); 144 | memcpy(value_ptr, value, map->value_size); 145 | 146 | dl_list_insert(head, &new_elem->hash_node); 147 | if (old_elem) { 148 | dl_list_remove(&old_elem->hash_node); 149 | free(old_elem); 150 | } else { 151 | hmap->count++; 152 | } 153 | 154 | return 0; 155 | } 156 | 157 | int 158 | ubpf_hashmap_delete(struct ubpf_map *map, const void *key) 159 | { 160 | struct hmap_elem *elem; 161 | struct hashmap *hmap = map->data; 162 | 163 | uint32_t hash = ubpf_hashmap_hash(key, map->key_size); 164 | struct dl_list *head = select_bucket(hmap, hash); 165 | elem = lookup_elem_raw(head, hash, key, map->key_size); 166 | 167 | if (!elem) { 168 | return -4; 169 | } 170 | 171 | dl_list_remove(&elem->hash_node); 172 | free(elem); 173 | hmap->count--; 174 | 175 | return 0; 176 | } 177 | -------------------------------------------------------------------------------- /ubpf/src/ubpf_hashmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Orange 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 | #ifndef UBPF_HASHMAP_H 17 | #define UBPF_HASHMAP_H 1 18 | 19 | #include "inc/utils.h" 20 | 21 | #include "lookup3.h" 22 | #include "ubpf_int.h" 23 | 24 | #define ALIGNED_VAR(N) __attribute__((aligned(N))) 25 | #define __round_mask(x, y) ((__typeof__(x))((y)-1)) 26 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) 27 | /* 28 | * Compute the next highest power of 2 of 32-bit x. 29 | */ 30 | #define round_up_pow_of_two(x) \ 31 | ({ uint32_t v = x; \ 32 | v--; \ 33 | v |= v >> 1; \ 34 | v |= v >> 2; \ 35 | v |= v >> 4; \ 36 | v |= v >> 8; \ 37 | v |= v >> 16; \ 38 | ++v; }) 39 | 40 | void *ubpf_hashmap_create(const struct ubpf_map *map); 41 | unsigned int ubpf_hashmap_size(const struct ubpf_map *map); 42 | unsigned int ubpf_hashmap_dump(const struct ubpf_map *map, void *data); 43 | void *ubpf_hashmap_lookup(const struct ubpf_map *map, const void *key); 44 | int ubpf_hashmap_update(struct ubpf_map *map, const void *key, void *value); 45 | int ubpf_hashmap_delete(struct ubpf_map *map, const void *key); 46 | 47 | /* 48 | * Double linked list 49 | */ 50 | struct dl_list { 51 | struct dl_list *prev; /* Previous list element. */ 52 | struct dl_list *next; /* Next list element. */ 53 | }; 54 | 55 | /* Inserts 'elem' just before 'before'. */ 56 | static inline void 57 | dl_list_insert(struct dl_list *before, struct dl_list *elem) 58 | { 59 | elem->prev = before->prev; 60 | elem->next = before; 61 | before->prev->next = elem; 62 | before->prev = elem; 63 | } 64 | 65 | /* Removes 'elem' from its list and returns the element that followed it. 66 | Undefined behavior if 'elem' is not in a list. */ 67 | static inline struct dl_list * 68 | dl_list_remove(struct dl_list *elem) 69 | { 70 | elem->prev->next = elem->next; 71 | elem->next->prev = elem->prev; 72 | return elem->next; 73 | } 74 | 75 | #define LIST_FOR_EACH(ITER, MEMBER, LIST) \ 76 | for (INIT_CONTAINER(ITER, (LIST)->next, MEMBER); \ 77 | &(ITER)->MEMBER != (LIST); \ 78 | ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER)) 79 | 80 | struct hashmap { 81 | struct dl_list *buckets; 82 | uint32_t count; 83 | uint32_t nb_buckets; 84 | uint32_t elem_size; 85 | }; 86 | 87 | struct hmap_elem { 88 | struct dl_list hash_node; 89 | uint32_t hash; 90 | char key[0] ALIGNED_VAR(8); 91 | }; 92 | 93 | static const struct ubpf_map_ops ubpf_hashmap_ops = { 94 | .map_size = ubpf_hashmap_size, 95 | .map_dump = ubpf_hashmap_dump, 96 | .map_lookup = ubpf_hashmap_lookup, 97 | .map_update = ubpf_hashmap_update, 98 | .map_delete = ubpf_hashmap_delete, 99 | .map_add = NULL, 100 | }; 101 | 102 | #define BPF_KEY_IS_HASH 1 103 | 104 | #endif -------------------------------------------------------------------------------- /ubpf/src/ubpf_hashmap.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/ubpf_hashmap.o -------------------------------------------------------------------------------- /ubpf/src/ubpf_int.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Big Switch Networks, Inc 3 | * Copyright 2022 Axbryd 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #ifndef UBPF_INT_H 19 | #define UBPF_INT_H 20 | 21 | #include 22 | #include "ebpf.h" 23 | #include "inc/hmap.h" 24 | 25 | #define MAX_INSTS 65536 26 | #define STACK_SIZE 512 27 | #define NB_FUNC_ARGS 5 28 | #define MAX_SIZE_ARG 8 29 | #define PKT_HEADROOM 64 30 | #define PKT_TAILROOM 64 31 | 32 | struct ebpf_inst; 33 | typedef uint64_t (*ext_func)(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4); 34 | 35 | enum ubfp_func_id { 36 | MAP_LOOKUP = 1, 37 | MAP_UPDATE = 2, 38 | MAP_DELETE = 3, 39 | MAP_ADD = 4, 40 | TIME_GET_NS = 5, 41 | HASH = 6, 42 | GET_SMP_PROCESSOR_ID = 8, 43 | CSUM_DIFF = 28, 44 | XDP_ADJUST_HEAD = 44, 45 | REDIRECT_MAP = 51, 46 | XDP_ADJUST_TAIL = 65, 47 | }; 48 | 49 | enum ubpf_reg_type { 50 | UNINIT = 0, 51 | UNKNOWN = 1, 52 | NULL_VALUE = 2, 53 | IMM = 4, 54 | MAP_PTR = 8, 55 | MAP_VALUE_PTR = 16, 56 | PKT_PTR = 32, 57 | PKT_SIZE = 64, 58 | STACK_PTR = 128, 59 | XDP_MD_PTR = 256, 60 | }; 61 | 62 | enum ubpf_arg_size { 63 | SIZE_64 = 0, 64 | SIZE_MAP_KEY, 65 | SIZE_MAP_VALUE, 66 | SIZE_PTR_MAX, 67 | }; 68 | 69 | struct ubpf_func_proto { 70 | ext_func func; 71 | enum ubpf_reg_type arg_types[NB_FUNC_ARGS]; 72 | enum ubpf_arg_size arg_sizes[NB_FUNC_ARGS]; 73 | enum ubpf_reg_type ret; 74 | }; 75 | 76 | enum ubpf_map_type { 77 | UBPF_MAP_TYPE_UNSPEC = 0, 78 | UBPF_MAP_TYPE_HASHMAP = 1, 79 | UBPF_MAP_TYPE_ARRAY = 2, 80 | UBPF_MAP_TYPE_PER_CPU_HASHMAP = 5, 81 | UBPF_MAP_TYPE_PER_CPU_ARRAY = 6, 82 | UBPF_MAP_TYPE_PER_CPU_LRU_HASH = 9, 83 | UBPF_MAP_TYPE_LPM_TRIE = 11, 84 | UBPF_MAP_TYPE_ARRAY_OF_MAPS = 12, 85 | UBPF_MAP_TYPE_DEVMAP = 14, 86 | }; 87 | 88 | struct ubpf_map_def { 89 | enum ubpf_map_type type; 90 | unsigned int key_size; 91 | unsigned int value_size; 92 | unsigned int max_entries; 93 | unsigned int nb_hash_functions; 94 | }; 95 | 96 | struct ubpf_map; 97 | 98 | struct ubpf_map_ops { 99 | unsigned int (*map_size)(const struct ubpf_map *map); 100 | unsigned int (*map_dump)(const struct ubpf_map *map, void *data); 101 | void *(*map_lookup)(const struct ubpf_map *map, const void *key); 102 | int (*map_update)(struct ubpf_map *map, const void *key, void *value); 103 | int (*map_delete)(struct ubpf_map *map, const void *key); 104 | int (*map_add)(struct ubpf_map *map, void *value); 105 | }; 106 | 107 | struct ubpf_map { 108 | enum ubpf_map_type type; 109 | struct ubpf_map_ops ops; 110 | unsigned int key_size; 111 | unsigned int value_size; 112 | unsigned int max_entries; 113 | void *data; 114 | }; 115 | 116 | struct ubpf_vm { 117 | //ovs_be16 filter_prog; 118 | struct hmap_node hmap_node; 119 | struct ebpf_inst *insts; 120 | uint16_t num_insts; 121 | ubpf_jit_fn jitted; 122 | size_t jitted_size; 123 | struct ubpf_func_proto *ext_funcs; 124 | const char **ext_func_names; 125 | struct ubpf_map **ext_maps; 126 | const char **ext_map_names; 127 | uint16_t nb_maps; 128 | bool bounds_check_enabled; 129 | }; 130 | 131 | char *ubpf_error(const char *fmt, ...); 132 | unsigned int ubpf_lookup_registered_function(struct ubpf_vm *vm, const char *name); 133 | struct ubpf_map *ubpf_lookup_registered_map(struct ubpf_vm *vm, const char *name); 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /ubpf/src/ubpf_loader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Big Switch Networks, Inc 3 | * Copyright 2022 Axbryd 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | #define _GNU_SOURCE 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "ubpf_int.h" 26 | #include 27 | #include "ubpf_array.c" 28 | #include "ubpf_hashmap.h" 29 | 30 | #define MAX_SECTIONS 32 31 | 32 | #ifndef EM_BPF 33 | #define EM_BPF 247 34 | #endif 35 | 36 | struct bounds { 37 | const void *base; 38 | uint64_t size; 39 | }; 40 | 41 | struct section { 42 | const Elf64_Shdr *shdr; 43 | const void *data; 44 | uint64_t size; 45 | }; 46 | 47 | static const void * 48 | bounds_check(struct bounds *bounds, uint64_t offset, uint64_t size) 49 | { 50 | if (offset + size > bounds->size || offset + size < offset) { 51 | return NULL; 52 | } 53 | return (void *)((uint64_t)bounds->base + offset); 54 | } 55 | 56 | int 57 | ubpf_load_elf(struct ubpf_vm *vm, const void *elf, size_t elf_size, char **errmsg) 58 | { 59 | struct bounds b = { .base=elf, .size=elf_size }; 60 | void *text_copy = NULL, *str_copy = NULL; 61 | struct ubpf_map *map = NULL; 62 | int i; 63 | 64 | const Elf64_Ehdr *ehdr = bounds_check(&b, 0, sizeof(*ehdr)); 65 | if (!ehdr) { 66 | *errmsg = ubpf_error("not enough data for ELF header"); 67 | goto error; 68 | } 69 | 70 | if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { 71 | *errmsg = ubpf_error("wrong magic"); 72 | goto error; 73 | } 74 | 75 | if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) { 76 | *errmsg = ubpf_error("wrong class"); 77 | goto error; 78 | } 79 | 80 | if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { 81 | *errmsg = ubpf_error("wrong byte order"); 82 | goto error; 83 | } 84 | 85 | if (ehdr->e_ident[EI_VERSION] != 1) { 86 | *errmsg = ubpf_error("wrong version"); 87 | goto error; 88 | } 89 | 90 | if (ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) { 91 | *errmsg = ubpf_error("wrong OS ABI"); 92 | goto error; 93 | } 94 | 95 | if (ehdr->e_type != ET_REL) { 96 | *errmsg = ubpf_error("wrong type, expected relocatable"); 97 | goto error; 98 | } 99 | 100 | if (ehdr->e_machine != EM_NONE && ehdr->e_machine != EM_BPF) { 101 | *errmsg = ubpf_error("wrong machine, expected none or EM_BPF"); 102 | goto error; 103 | } 104 | 105 | if (ehdr->e_shnum > MAX_SECTIONS) { 106 | *errmsg = ubpf_error("too many sections"); 107 | goto error; 108 | } 109 | 110 | /* Parse section headers into an array */ 111 | struct section sections[MAX_SECTIONS]; 112 | for (i = 0; i < ehdr->e_shnum; i++) { 113 | const Elf64_Shdr *shdr = bounds_check(&b, ehdr->e_shoff + i*ehdr->e_shentsize, sizeof(*shdr)); 114 | if (!shdr) { 115 | *errmsg = ubpf_error("bad section header offset or size"); 116 | goto error; 117 | } 118 | 119 | const void *data = bounds_check(&b, shdr->sh_offset, shdr->sh_size); 120 | if (!data) { 121 | *errmsg = ubpf_error("bad section offset or size"); 122 | goto error; 123 | } 124 | 125 | sections[i].shdr = shdr; 126 | sections[i].data = data; 127 | sections[i].size = shdr->sh_size; 128 | } 129 | 130 | /* Find first text section */ 131 | int text_shndx = 0; 132 | for (i = 0; i < ehdr->e_shnum; i++) { 133 | const Elf64_Shdr *shdr = sections[i].shdr; 134 | if (shdr->sh_type == SHT_PROGBITS && 135 | shdr->sh_flags == (SHF_ALLOC|SHF_EXECINSTR)) { 136 | text_shndx = i; 137 | break; 138 | } 139 | } 140 | 141 | if (!text_shndx) { 142 | *errmsg = ubpf_error("text section not found"); 143 | goto error; 144 | } 145 | struct section *text = §ions[text_shndx]; 146 | 147 | /* Find first .data section */ 148 | int data_shndx = 0; 149 | for (i = 0; i < ehdr->e_shnum; i++) { 150 | const Elf64_Shdr *shdr = sections[i].shdr; 151 | if (shdr->sh_type == SHT_PROGBITS && 152 | shdr->sh_flags == (SHF_ALLOC|SHF_WRITE)) { 153 | data_shndx = i; 154 | break; 155 | } 156 | } 157 | struct section *data = NULL; 158 | if (data_shndx) { 159 | data = §ions[data_shndx]; 160 | } 161 | 162 | /* Find first .rodata.str section if any. */ 163 | int str_shndx = 0; 164 | for (i = 0; i < ehdr->e_shnum; i++) { 165 | const Elf64_Shdr *shdr = sections[i].shdr; 166 | if (shdr->sh_type == SHT_PROGBITS && 167 | shdr->sh_flags == (SHF_ALLOC|SHF_MERGE|SHF_STRINGS)) { 168 | str_shndx = i; 169 | break; 170 | } 171 | } 172 | struct section *str = NULL; 173 | if (str_shndx) { 174 | str = §ions[str_shndx]; 175 | 176 | /* May need to modify text for specifiers, so make a copy */ 177 | str_copy = malloc(str->size); 178 | if (!str_copy) { 179 | *errmsg = ubpf_error("failed to allocate memory"); 180 | goto error; 181 | } 182 | memcpy(str_copy, str->data, str->size); 183 | } 184 | 185 | /* May need to modify text for relocations, so make a copy */ 186 | text_copy = malloc(text->size); 187 | memcpy(text_copy, text->data, text->size); 188 | 189 | /* Process each relocation section */ 190 | for (i = 0; i < ehdr->e_shnum; i++) { 191 | struct section *rel = §ions[i]; 192 | if (rel->shdr->sh_type != SHT_REL) { 193 | continue; 194 | } else if (rel->shdr->sh_info != text_shndx) { 195 | continue; 196 | } 197 | 198 | const Elf64_Rel *rs = rel->data; 199 | 200 | if (rel->shdr->sh_link >= ehdr->e_shnum) { 201 | *errmsg = ubpf_error("bad symbol table section index"); 202 | goto error; 203 | } 204 | 205 | struct section *symtab = §ions[rel->shdr->sh_link]; 206 | const Elf64_Sym *syms = symtab->data; 207 | uint32_t num_syms = symtab->size/sizeof(syms[0]); 208 | 209 | if (symtab->shdr->sh_link >= ehdr->e_shnum) { 210 | *errmsg = ubpf_error("bad string table section index"); 211 | goto error; 212 | } 213 | 214 | struct section *strtab = §ions[symtab->shdr->sh_link]; 215 | const char *strings = strtab->data; 216 | 217 | int j; 218 | for (j = 0; j < rel->size/sizeof(Elf64_Rel); j++) { 219 | const Elf64_Rel *r = &rs[j]; 220 | 221 | if (ELF64_R_TYPE(r->r_info) != ET_EXEC && ELF64_R_TYPE(r->r_info) != ET_REL) { 222 | *errmsg = ubpf_error("bad relocation type %u", ELF64_R_TYPE(r->r_info)); 223 | goto error; 224 | } 225 | 226 | uint32_t sym_idx = ELF64_R_SYM(r->r_info); 227 | 228 | if (sym_idx >= num_syms) { 229 | *errmsg = ubpf_error("bad symbol index"); 230 | goto error; 231 | } 232 | 233 | const Elf64_Sym *sym = &syms[sym_idx]; 234 | 235 | if (sym->st_name >= strtab->size) { 236 | *errmsg = ubpf_error("bad symbol name"); 237 | goto error; 238 | } 239 | 240 | const char *sym_name = strings + sym->st_name; 241 | 242 | if (r->r_offset + 8 > text->size) { 243 | *errmsg = ubpf_error("bad relocation offset"); 244 | goto error; 245 | } 246 | 247 | switch(ELF64_R_TYPE(r->r_info)) { 248 | case 1: 249 | { 250 | int sym_shndx = sym->st_shndx; 251 | if (sym_shndx == data_shndx) { 252 | if (!data_shndx) { 253 | *errmsg = ubpf_error("missing data section"); 254 | goto error; 255 | } 256 | 257 | map = ubpf_lookup_registered_map(vm, sym_name); 258 | if(!map) { 259 | uint64_t sym_data_offset = sym->st_value; 260 | if (sym_data_offset + sizeof(struct ubpf_map_def) > data->size) { 261 | *errmsg = ubpf_error("bad data offset"); 262 | goto error; 263 | } 264 | const struct ubpf_map_def *map_def = (void *)((uint64_t)data->data + sym_data_offset); 265 | 266 | map = malloc(sizeof(struct ubpf_map)); 267 | map->type = map_def->type; 268 | map->key_size = map_def->key_size; 269 | map->value_size = map_def->value_size; 270 | map->max_entries = map_def->max_entries; 271 | 272 | switch(map_def->type) { 273 | case UBPF_MAP_TYPE_ARRAY: 274 | map->ops = ubpf_array_ops; 275 | map->data = ubpf_array_create(map_def); 276 | break; 277 | case UBPF_MAP_TYPE_HASHMAP: 278 | map->ops = ubpf_hashmap_ops; 279 | map->data = ubpf_hashmap_create(map_def); 280 | break; 281 | default: 282 | *errmsg = ubpf_error("unrecognized map type: %d", map_def->type); 283 | goto error_map; 284 | } 285 | 286 | if (!map->data) { 287 | *errmsg = ubpf_error("failed to allocate memory"); 288 | goto error_map; 289 | } 290 | 291 | int result = ubpf_register_map(vm, sym_name, map); 292 | if (result == -1) { 293 | *errmsg = ubpf_error("failed to register variable '%s'", sym_name); 294 | goto error_map; 295 | } 296 | } 297 | 298 | *(uint32_t *)((uint64_t)text_copy + r->r_offset + 4) = (uint32_t)((uint64_t)map); 299 | *(uint32_t *)((uint64_t)text_copy + r->r_offset + sizeof(struct ebpf_inst) + 4) = (uint32_t)((uint64_t)map >> 32); 300 | 301 | } else if (sym_shndx == str_shndx) { 302 | if (!str_shndx) { 303 | *errmsg = ubpf_error("missing string section"); 304 | goto error; 305 | } 306 | 307 | uint64_t sym_data_offset = sym->st_value; 308 | const char *string = (void *)((uint64_t)str_copy + sym_data_offset); 309 | size_t str_len = strlen(string); 310 | if (sym_data_offset + str_len > str->size) { 311 | *errmsg = ubpf_error("bad data offset"); 312 | goto error; 313 | } 314 | 315 | *(uint32_t *)((uint64_t)text_copy + r->r_offset + 4) = (uint32_t)((uint64_t)string); 316 | *(uint32_t *)((uint64_t)text_copy + r->r_offset + sizeof(struct ebpf_inst) + 4) = (uint32_t)((uint64_t)string >> 32); 317 | } 318 | 319 | break; 320 | } 321 | 322 | case 2: 323 | { 324 | unsigned int imm = ubpf_lookup_registered_function(vm, sym_name); 325 | if (imm == -1) { 326 | *errmsg = ubpf_error("function '%s' not found", sym_name); 327 | goto error; 328 | } 329 | 330 | *(uint32_t *)((uint64_t)text_copy + r->r_offset + 4) = imm; 331 | 332 | break; 333 | } 334 | 335 | default: ; 336 | } 337 | } 338 | } 339 | 340 | int rv = ubpf_load(vm, text_copy, sections[text_shndx].size, errmsg); 341 | free(text_copy); 342 | return rv; 343 | 344 | error_map: 345 | free(map); 346 | error: 347 | free(text_copy); 348 | return -1; 349 | } -------------------------------------------------------------------------------- /ubpf/src/ubpf_lpm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Axbryd 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 "ubpf_lpm.h" 19 | #include "uthash.h" 20 | 21 | static inline void 22 | lpm_apply_mask(uint32_t key_size, uint32_t prefix, uint32_t **val) 23 | { 24 | uint32_t *out = (uint32_t *)val; 25 | 26 | switch (key_size) { 27 | // IPv4 addresses 28 | case 8: 29 | out[0] &= (uint32_t) (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF; 30 | break; 31 | // IPv6 addresses 32 | case 20: 33 | if (prefix > 128) 34 | break; 35 | if (prefix >= 96 && prefix < 128) { 36 | out[3] &= (uint32_t) (0xFFFFFFFF << (32 - prefix%32)) & 0xFFFFFFFF; 37 | out[0] = out[1] = out[2] = 0; 38 | } else if (prefix >= 64 && prefix < 96) { 39 | out[2] &= (uint32_t) (0xFFFFFFFF << (32 - prefix%32)) & 0xFFFFFFFF; 40 | out[0] = out[1] = 0; 41 | } else if (prefix >= 32 && prefix < 64) { 42 | out[1] &= (uint32_t) (0xFFFFFFFF << (32 - prefix%32)) & 0xFFFFFFFF; 43 | out[0]= 0; 44 | } else { 45 | out[0] &= (uint32_t) (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF; 46 | } 47 | break; 48 | default: 49 | logm(SL4C_ERROR, "Key size %d not supported", key_size); 50 | break; 51 | } 52 | } 53 | 54 | void * 55 | ubpf_lpm_create(const struct ubpf_map *map) 56 | { 57 | uint8_t prefix_len; 58 | struct ubpf_lpm *lpm = malloc(sizeof(struct ubpf_lpm)); 59 | 60 | switch (map->key_size) { 61 | // IPv4 addresses 62 | case 8: 63 | prefix_len = 32; 64 | break; 65 | // IPv6 addresses 66 | case 20: 67 | prefix_len = 128; 68 | break; 69 | default: 70 | logm(SL4C_ERROR, "Key size %d not supported", map->key_size); 71 | return NULL; 72 | } 73 | 74 | lpm->lpm_size = prefix_len; 75 | lpm->count = 0; 76 | lpm->lpm_hmaps = malloc(prefix_len * sizeof(struct lpm_hmap *)); 77 | for (int i=0; ilpm_size; i++) 78 | lpm->lpm_hmaps[i] = NULL; 79 | 80 | return lpm; 81 | } 82 | 83 | unsigned int 84 | ubpf_lpm_size(const struct ubpf_map *map) 85 | { 86 | struct ubpf_lpm *lpm = (struct ubpf_lpm *) map->data; 87 | return lpm->count; 88 | } 89 | 90 | void * 91 | ubpf_lpm_lookup(const struct ubpf_map *map, const void *key) 92 | { 93 | struct ubpf_lpm *lpm = (struct ubpf_lpm *) map->data; 94 | uint32_t masked_key[4] = {0}; 95 | 96 | memcpy(masked_key, key+4, map->key_size-4); 97 | 98 | masked_key[0] = be32toh(masked_key[0]); 99 | masked_key[1] = be32toh(masked_key[1]); 100 | masked_key[2] = be32toh(masked_key[2]); 101 | masked_key[3] = be32toh(masked_key[3]); 102 | 103 | for (int i=lpm->lpm_size-1; i>-1; i--) { 104 | struct lpm_hmap *elem = NULL; 105 | 106 | lpm_apply_mask(map->key_size, i+1, (uint32_t **) &masked_key); 107 | 108 | HASH_FIND(hh, lpm->lpm_hmaps[i], 109 | masked_key, map->key_size - 4, elem); 110 | if (elem) 111 | return elem->value; 112 | } 113 | return NULL; 114 | } 115 | 116 | int 117 | ubpf_lpm_update(struct ubpf_map *map, const void *key, void *value) 118 | { 119 | struct ubpf_lpm *lpm = map->data; 120 | struct lpm_hmap *old_elem = NULL; 121 | 122 | old_elem = ubpf_lpm_lookup(map, key); 123 | 124 | if (!old_elem && (lpm->count >= map->max_entries)) { 125 | return -4; 126 | } 127 | 128 | if (old_elem) { 129 | memcpy(old_elem->value, value, map->value_size); 130 | } else { 131 | struct lpm_hmap *new_elem; 132 | struct lpm_hmap **head; 133 | uint32_t prefix = be32toh(*(uint32_t *)key); 134 | 135 | new_elem = malloc(sizeof(struct lpm_hmap)); 136 | memcpy(new_elem->key, key+4, map->key_size); 137 | 138 | new_elem->key[0] = be32toh(new_elem->key[0]); 139 | new_elem->key[1] = be32toh(new_elem->key[1]); 140 | new_elem->key[2] = be32toh(new_elem->key[2]); 141 | new_elem->key[3] = be32toh(new_elem->key[3]); 142 | 143 | lpm_apply_mask(map->key_size, prefix, (uint32_t **) &new_elem->key); 144 | 145 | new_elem->value = malloc(map->value_size); 146 | memcpy(new_elem->value, value, map->value_size); 147 | 148 | head = &lpm->lpm_hmaps[prefix - 1]; 149 | 150 | HASH_ADD(hh, *head, key, map->key_size - 4, new_elem); 151 | 152 | lpm->count++; 153 | } 154 | 155 | return 0; 156 | } 157 | 158 | int 159 | ubpf_lpm_delete(struct ubpf_map *map, const void *key) 160 | { 161 | struct ubpf_lpm *lpm = map->data; 162 | struct lpm_hmap *elem = NULL; 163 | int position; 164 | 165 | for (int i=lpm->lpm_size - 1; i>-1; i--) { 166 | HASH_FIND(hh, lpm->lpm_hmaps[i], 167 | key+4, map->key_size - 4, elem); 168 | if (elem) { 169 | position = i; 170 | break; 171 | } 172 | } 173 | 174 | if (!elem) 175 | return -4; 176 | 177 | HASH_DEL(lpm->lpm_hmaps[position], elem); 178 | 179 | free(elem->value); 180 | free(elem); 181 | 182 | return 0; 183 | } 184 | 185 | unsigned int 186 | ubpf_lpm_dump(const struct ubpf_map *map, void *data) 187 | { 188 | struct ubpf_lpm *lpm = map->data; 189 | (void)data; 190 | return lpm->count; 191 | } 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /ubpf/src/ubpf_lpm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Axbryd 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 UBPF_UBPF_LPM_H 18 | #define UBPF_UBPF_LPM_H 19 | 20 | #include "ubpf_int.h" 21 | #include "uthash.h" 22 | 23 | void *ubpf_lpm_create(const struct ubpf_map *map); 24 | unsigned int ubpf_lpm_size(const struct ubpf_map *map); 25 | unsigned int ubpf_lpm_dump(const struct ubpf_map *map, void *data); 26 | void *ubpf_lpm_lookup(const struct ubpf_map *map, const void *key); 27 | int ubpf_lpm_update(struct ubpf_map *map, const void *key, void *value); 28 | int ubpf_lpm_delete(struct ubpf_map *map, const void *key); 29 | 30 | struct lpm_hmap { 31 | UT_hash_handle hh; 32 | uint32_t key[4]; 33 | void *value; 34 | }; 35 | 36 | typedef struct ubpf_lpm { 37 | struct lpm_hmap **lpm_hmaps; // array of hashmaps 38 | uint8_t lpm_size; 39 | unsigned int count; 40 | } ubpf_lpm_t; 41 | 42 | static const struct ubpf_map_ops ubpf_lpm_ops = { 43 | .map_size = ubpf_lpm_size, 44 | .map_dump = ubpf_lpm_dump, 45 | .map_lookup = ubpf_lpm_lookup, 46 | .map_update = ubpf_lpm_update, 47 | .map_delete = ubpf_lpm_delete, 48 | .map_add = NULL, 49 | }; 50 | 51 | #endif //UBPF_UBPF_LPM_H 52 | -------------------------------------------------------------------------------- /ubpf/src/ubpf_lpm.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/ubpf_lpm.o -------------------------------------------------------------------------------- /ubpf/src/ubpf_vm.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/ubpf/src/ubpf_vm.o -------------------------------------------------------------------------------- /use_cases/katran/.gen/katran.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/katran/.gen/katran.bin -------------------------------------------------------------------------------- /use_cases/katran/.gen/katran_maps.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "offsets": [ 5 | 840, 6 | 1210 7 | ], 8 | "type": 2, 9 | "key_size": 4, 10 | "value_size": 8, 11 | "max_entries": 16, 12 | "name": "ctl_array" 13 | }, 14 | { 15 | "id": 1, 16 | "offsets": [ 17 | 352, 18 | 465, 19 | 518, 20 | 850, 21 | 1060, 22 | 1219 23 | ], 24 | "type": 6, 25 | "key_size": 4, 26 | "value_size": 16, 27 | "max_entries": 1024, 28 | "name": "stats" 29 | }, 30 | { 31 | "id": 2, 32 | "offsets": [ 33 | 865, 34 | 1233 35 | ], 36 | "type": 6, 37 | "key_size": 4, 38 | "value_size": 16, 39 | "max_entries": 4096, 40 | "name": "reals_stats" 41 | }, 42 | { 43 | "id": 3, 44 | "offsets": [ 45 | 506, 46 | 816, 47 | 1048, 48 | 1187 49 | ], 50 | "type": 2, 51 | "key_size": 4, 52 | "value_size": 20, 53 | "max_entries": 4096, 54 | "name": "reals" 55 | }, 56 | { 57 | "id": 4, 58 | "offsets": [ 59 | 807, 60 | 1178 61 | ], 62 | "type": 2, 63 | "key_size": 4, 64 | "value_size": 4, 65 | "max_entries": 33554944, 66 | "name": "ch_rings" 67 | }, 68 | { 69 | "id": 5, 70 | "offsets": [ 71 | 371, 72 | 483 73 | ], 74 | "type": 12, 75 | "key_size": 4, 76 | "value_size": 4, 77 | "max_entries": 128, 78 | "name": "lru_mapping" 79 | }, 80 | { 81 | "id": 6, 82 | "offsets": [ 83 | 325, 84 | 333, 85 | 434, 86 | 442 87 | ], 88 | "type": 1, 89 | "key_size": 20, 90 | "value_size": 8, 91 | "max_entries": 512, 92 | "name": "vip_map" 93 | }, 94 | { 95 | "comment": "ADDED_BY_HAND", 96 | "id": 7, 97 | "offsets": [], 98 | "type": 1, 99 | "key_size": 40, 100 | "value_size": 12, 101 | "max_entries": 1024, 102 | "name": "lru_cache_0" 103 | } 104 | ] 105 | -------------------------------------------------------------------------------- /use_cases/katran/katran.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/katran/katran.bin -------------------------------------------------------------------------------- /use_cases/katran/katran.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/katran/katran.o -------------------------------------------------------------------------------- /use_cases/katran/katran.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/katran/katran.pcap -------------------------------------------------------------------------------- /use_cases/katran/katran_map_entries.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "vip_map", "comment": "ipv4 | udp with flags", 4 | "map_id": 6, "key": "01 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 00", 5 | "key_info": "vip (16B) | port(16B) | proto(1B) | pad(1B) ", 6 | "value": "00 00 00 00 00 00 00 00", "value_info": "flags(4B) | vip_num (4B)" 7 | }, 8 | { 9 | "name": "vip_map", "comment": "ipv4 | tcp with flags", 10 | "map_id": 6, "key": "01 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00", 11 | "key_info": "vip (16B) | port(16B) | proto(1B) | pad(1B) ", 12 | "value": "09 00 00 00 00 00 00 00", "value_info": "flags(4B) | vip_num (4B)" 13 | }, 14 | { 15 | "name": "vip_map", "comment": "ipv6 | udp with flags", 16 | "map_id": 6, "key": "11 11 00 00 00 00 00 00 00 00 00 00 00 00 11 11 00 00 11 00", 17 | "key_info": "vip (16B) | port(16B) | proto(1B) | pad(1B) ", 18 | "value": "01 00 00 00 01 00 00 00", "value_info": "flags(4B) | vip_num (4B)" 19 | }, 20 | { 21 | "name": "vip_map", "comment": "ipv6 | tcp with flags", 22 | "map_id": 6, "key": "11 11 00 00 00 00 00 00 00 00 00 00 00 00 11 11 00 00 06 00", 23 | "key_info": "vip (16B) | port(16B) | proto(1B) | pad(1B) ", 24 | "value": "01 00 00 00 01 00 00 00", "value_info": "flags(4B) | vip_num (4B)" 25 | }, 26 | { 27 | "name": "vip_map", "comment": "ipv6 | tcp without flags", 28 | "map_id": 6, "key": "a1 a1 00 00 00 00 00 00 00 00 00 00 00 00 a1 a1 00 00 06 00", 29 | "key_info": "vip (16B) | port(16B) | proto(1B) | pad(1B) ", 30 | "value": "09 00 00 00 01 00 00 00", "value_info": "flags(4B) | vip_num (4B)" 31 | }, 32 | { 33 | "comment": "array_of_maps", 34 | "name": "lru_mapping", 35 | "map_id": 5, "key": "00 00 00 00", "key_info": "num_cpu (4B)", 36 | "value": "07", "value_info" : "LRU MAP POINTER" 37 | }, 38 | { 39 | "name": "reals", "comment": "ipv4", 40 | "map_id": 3, "key": "00 00 00 00", "key_info": "u32 position", 41 | "value": "ee ee ee ee 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", 42 | "value_info": "u32[4] real_ip.dst | flags | pad" 43 | }, 44 | { 45 | "name": "reals", "comment": "ipv6", 46 | "map_id": 3, "key": "01 00 00 00", "key_info": "u32 position", 47 | "value": "ee ee 00 00 00 00 00 00 00 00 00 00 00 00 ee ee 01 00 00 00", 48 | "value_info": "u32[4] real_ip.dst | flags | pad" 49 | }, 50 | { 51 | "name": "reals", "comment": "ipv6", 52 | "map_id": 3, "key": "02 00 00 00", "key_info": "u32 position", 53 | "value": "ee ee 00 00 00 00 00 00 00 00 00 00 00 00 ee ee 01 00 00 00", 54 | "value_info": "u32[4] real_ip.dst | flags | pad" 55 | }, 56 | { 57 | "name": "ctl_array", 58 | "map_id": 0, "key": "00 00 00 00", "key_info": "u32 pos", 59 | "value": "aa bb cc dd ee ff 00 00", "value_info": "mac_address (6B) | pad(2)" 60 | }, 61 | { 62 | "name": "lru_cache_0", "comment": "ipv4 key | udp", 63 | "map_id": 7, "key": "0a 0a 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 00 00 00 00 00 00 00 00 00 00 aa aa bb bb 00 00 11 00 00 00", 64 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 65 | "value": "00 00 00 00 00 00 00 00 00 00 00 00", 66 | "value_info": "u32 pos | u64 time" 67 | }, 68 | { 69 | "name": "lru_cache_0", "comment": "ipv4 key | tcp", 70 | "map_id": 7, "key": "0a 0a 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 00 00 00 00 00 00 00 00 00 00 aa aa bb bb 00 00 06 00 00 00", 71 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 72 | "value": "00 00 00 00 00 00 00 00 00 00 00 00", 73 | "value_info": "u32 pos | u64 time" 74 | }, 75 | { 76 | "name": "lru_cache_0", "comment": "ipv4 key | udp", 77 | "map_id": 7, "key": "0a 0a 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 bb bb 00 00 11 00 00 00", 78 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 79 | "value": "00 00 00 00 00 00 00 00 00 00 00 00", 80 | "value_info": "u32 pos | u64 time" 81 | }, 82 | { 83 | "name": "lru_cache_0", "comment": "ipv4 key | tcp", 84 | "map_id": 7, "key": "0a 0a 0a 0a 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 bb bb 00 00 06 00 00 00", 85 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 86 | "value": "00 00 00 00 00 00 00 00 00 00 00 00", 87 | "value_info": "u32 pos | u64 time" 88 | }, 89 | { 90 | "name": "lru_cache_0", "comment": "ipv6 key | udp", 91 | "map_id": 7, "key": "aa aa 00 00 00 00 00 00 00 00 00 00 00 00 aa aa 11 11 00 00 00 00 00 00 00 00 00 00 00 00 11 11 bb bb 00 00 11 00 00 00", 92 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 93 | "value": "01 00 00 00 00 00 00 00 00 00 00 00", 94 | "value_info": "u32 pos | u64 time" 95 | }, 96 | { 97 | "name": "lru_cache_0", "comment": "ipv6 key | tcp", 98 | "map_id": 7, "key": "aa aa 00 00 00 00 00 00 00 00 00 00 00 00 aa aa 11 11 00 00 00 00 00 00 00 00 00 00 00 00 11 11 bb bb 00 00 06 00 00 00", 99 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 100 | "value": "01 00 00 00 00 00 00 00 00 00 00 00", 101 | "value_info": "u32 pos | u64 time" 102 | }, 103 | { 104 | "name": "lru_cache_0", "comment": "ipv6 key | udp", 105 | "map_id": 7, "key": "aa aa 00 00 00 00 00 00 00 00 00 00 00 00 aa aa 11 11 00 00 00 00 00 00 00 00 00 00 00 00 11 11 00 00 00 00 11 00 00 00", 106 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 107 | "value": "01 00 00 00 00 00 00 00 00 00 00 00", 108 | "value_info": "u32 pos | u64 time" 109 | }, 110 | { 111 | "name": "lru_cache_0", "comment": "ipv6 key | tcp", 112 | "map_id": 7, "key": "aa aa 00 00 00 00 00 00 00 00 00 00 00 00 aa aa 11 11 00 00 00 00 00 00 00 00 00 00 00 00 11 11 00 00 00 00 06 00 00 00", 113 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 114 | "value": "01 00 00 00 00 00 00 00 00 00 00 00", 115 | "value_info": "u32 pos | u64 time" 116 | }, 117 | { 118 | "name": "lru_cache_0", "comment": "ipv6 key | udp", 119 | "map_id": 7, "key": "11 11 00 00 00 00 00 00 00 00 00 00 00 00 11 11 a1 a1 00 00 00 00 00 00 00 00 00 00 00 00 a1 a1 bb bb 00 00 11 00 00 00", 120 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 121 | "value": "01 00 00 00 00 00 00 00 00 00 00 00", 122 | "value_info": "u32 pos | u64 time" 123 | }, 124 | { 125 | "name": "lru_cache_0", "comment": "ipv6 key | tcp", 126 | "map_id": 7, "key": "11 11 00 00 00 00 00 00 00 00 00 00 00 00 21 11 a1 a1 00 00 00 00 00 00 00 00 00 00 00 00 a1 a1 bb bb 00 00 06 00 00 00", 127 | "key_info": "ip.src | ip.dst | sport | dport | proto | pad(3)", 128 | "value": "01 00 00 00 00 00 00 00 00 00 00 00", 129 | "value_info": "u32 pos | u64 time" 130 | }, 131 | { 132 | "name": "ch_rings", 133 | "map_id": 4, "key": "4f 02 02 00", 134 | "value": "01 00 00 00" 135 | }, 136 | { 137 | "name": "vip_map", "comment": "ipv4 | udp with flags", 138 | "map_id": 6, "key": "0d 0d 0d 0d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 00", 139 | "key_info": "vip (16B) | port(16B) | proto(1B) | pad(1B) ", 140 | "value": "00 00 00 00 00 00 00 00", "value_info": "flags(4B) | vip_num (4B)" 141 | }, 142 | { 143 | "name": "ch_rings", 144 | "map_id": 4, "key": "56 79 00 00", 145 | "value": "02 00 00 00" 146 | }, 147 | { 148 | "name": "ch_rings", 149 | "map_id": 4, "key": "8c 43 01 00", 150 | "value": "01 00 00 00" 151 | }, 152 | { 153 | "name": "ch_rings", 154 | "map_id": 4, "key": "4e 02 01 00", 155 | "value": "02 00 00 00" 156 | } 157 | ] -------------------------------------------------------------------------------- /use_cases/katran/katran_maps.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "offsets": [ 5 | 840, 6 | 1210 7 | ], 8 | "type": 2, 9 | "key_size": 4, 10 | "value_size": 8, 11 | "max_entries": 16, 12 | "name": "ctl_array" 13 | }, 14 | { 15 | "id": 1, 16 | "offsets": [ 17 | 352, 18 | 465, 19 | 518, 20 | 850, 21 | 1060, 22 | 1219 23 | ], 24 | "type": 6, 25 | "key_size": 4, 26 | "value_size": 16, 27 | "max_entries": 1024, 28 | "name": "stats" 29 | }, 30 | { 31 | "id": 2, 32 | "offsets": [ 33 | 865, 34 | 1233 35 | ], 36 | "type": 6, 37 | "key_size": 4, 38 | "value_size": 16, 39 | "max_entries": 4096, 40 | "name": "reals_stats" 41 | }, 42 | { 43 | "id": 3, 44 | "offsets": [ 45 | 506, 46 | 816, 47 | 1048, 48 | 1187 49 | ], 50 | "type": 2, 51 | "key_size": 4, 52 | "value_size": 20, 53 | "max_entries": 4096, 54 | "name": "reals" 55 | }, 56 | { 57 | "id": 4, 58 | "offsets": [ 59 | 807, 60 | 1178 61 | ], 62 | "type": 2, 63 | "key_size": 4, 64 | "value_size": 4, 65 | "max_entries": 33554944, 66 | "name": "ch_rings" 67 | }, 68 | { 69 | "id": 5, 70 | "offsets": [ 71 | 371, 72 | 483 73 | ], 74 | "type": 12, 75 | "key_size": 4, 76 | "value_size": 4, 77 | "max_entries": 128, 78 | "name": "lru_mapping" 79 | }, 80 | { 81 | "id": 6, 82 | "offsets": [ 83 | 325, 84 | 333, 85 | 434, 86 | 442 87 | ], 88 | "type": 1, 89 | "key_size": 20, 90 | "value_size": 8, 91 | "max_entries": 512, 92 | "name": "vip_map" 93 | } 94 | ] -------------------------------------------------------------------------------- /use_cases/l2_acl/.gen/l2acl.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/l2_acl/.gen/l2acl.bin -------------------------------------------------------------------------------- /use_cases/l2_acl/.gen/l2acl_maps.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "offsets": [ 5 | 33 6 | ], 7 | "type": 1, 8 | "key_size": 6, 9 | "value_size": 4, 10 | "max_entries": 256, 11 | "name": "map" 12 | } 13 | ] -------------------------------------------------------------------------------- /use_cases/l2_acl/.gen/l2acl_mat.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "matches": [ 4 | { 5 | "type": "DontCare", 6 | "operand0": { 7 | "offset": 12, 8 | "len": 16, 9 | "field_manipulations": [], 10 | "type": "PacketField" 11 | } 12 | } 13 | ], 14 | "action": { 15 | "type": "XDPAction", 16 | "xdp_action": "xdp_pass" 17 | }, 18 | "priority": 2, 19 | "rule_metadata": { 20 | "jumped_insns": 17 21 | } 22 | }, 23 | { 24 | "matches": [ 25 | { 26 | "match_op": "==", 27 | "operand0": { 28 | "offset": 12, 29 | "len": 16, 30 | "field_manipulations": [], 31 | "type": "PacketField" 32 | }, 33 | "operand1": { 34 | "val": 8, 35 | "type": "Immediate" 36 | }, 37 | "type": "ACLMatch" 38 | } 39 | ], 40 | "action": { 41 | "map_id": 0, 42 | "pc": 35, 43 | "context": { 44 | "registers": { 45 | "1": { 46 | "val": 0, 47 | "type": "Immediate" 48 | }, 49 | "2": { 50 | "offset": -8, 51 | "type": "StackPointer" 52 | }, 53 | "3": { 54 | "offset": 8, 55 | "len": 8, 56 | "field_manipulations": [], 57 | "type": "PacketField" 58 | }, 59 | "10": { 60 | "offset": 0, 61 | "type": "StackPointer" 62 | } 63 | }, 64 | "stack": [ 65 | { 66 | "start": -8, 67 | "end": -4, 68 | "value_type": { 69 | "offset": 6, 70 | "len": 32, 71 | "field_manipulations": [], 72 | "type": "PacketField" 73 | } 74 | }, 75 | { 76 | "start": -4, 77 | "end": -2, 78 | "value_type": { 79 | "offset": 10, 80 | "len": 16, 81 | "field_manipulations": [], 82 | "type": "PacketField" 83 | } 84 | } 85 | ] 86 | }, 87 | "type": "MapAccess" 88 | }, 89 | "priority": 1, 90 | "rule_metadata": { 91 | "jumped_insns": 36 92 | } 93 | }, 94 | { 95 | "matches": [ 96 | { 97 | "match_op": "==", 98 | "operand0": { 99 | "offset": 12, 100 | "len": 16, 101 | "field_manipulations": [], 102 | "type": "PacketField" 103 | }, 104 | "operand1": { 105 | "val": 56710, 106 | "type": "Immediate" 107 | }, 108 | "type": "ACLMatch" 109 | } 110 | ], 111 | "action": { 112 | "type": "XDPAction", 113 | "xdp_action": "xdp_drop" 114 | }, 115 | "priority": 0, 116 | "rule_metadata": { 117 | "jumped_insns": 15 118 | } 119 | } 120 | ] -------------------------------------------------------------------------------- /use_cases/l2_acl/.gen/match_action_table_readable.txt: -------------------------------------------------------------------------------- 1 | hXDPc-acc Match Action Table: 2 | > size: 3*2B = 6B 3 | > fields: [Pkt(off: 12, len: 16b)] 4 | > content: 5 | 0: p0 | [56710] | xdp_drop 6 | 1: p1 | [8] | map #0, pc=35 7 | 2: p2 | [X] | xdp_pass 8 | -------------------------------------------------------------------------------- /use_cases/l2_acl/l2acl.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/l2_acl/l2acl.o -------------------------------------------------------------------------------- /use_cases/l2_acl/l2acl.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/l2_acl/l2acl.pcap -------------------------------------------------------------------------------- /use_cases/l2_acl/l2acl_map_entries.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "map_id": 0, "key": "cc cc cc cc cc cc", 4 | "value": "00 00 00 01" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /use_cases/l2_acl/src/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | 3 | XDP_TARGETS := l2acl 4 | USER_TARGETS := l2acl_user 5 | 6 | LLC ?= llc 7 | CLANG ?= clang 8 | CC := gcc 9 | 10 | LIBBPF_DIR = ../libbpf/src/ 11 | COMMON_DIR = ../common/ 12 | 13 | include $(COMMON_DIR)/common.mk 14 | COMMON_OBJS := $(COMMON_DIR)/common_params.o 15 | -------------------------------------------------------------------------------- /use_cases/l2_acl/src/l2acl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../common/parsing_helpers.h" 12 | 13 | #define BE_ETH_P_IP 8 14 | #define BE_ETH_P_IPV6 56710 15 | 16 | struct bpf_map_def SEC("maps") map = { 17 | .type = BPF_MAP_TYPE_HASH, 18 | .key_size = 6, 19 | .value_size = sizeof(__u32), 20 | .max_entries = 256, 21 | }; 22 | 23 | SEC("xdp") 24 | int toy_example(struct xdp_md *ctx) 25 | { 26 | void *data_end = (void *)(long)ctx->data_end; 27 | void *data = (void *)(long)ctx->data; 28 | void *lookup_res = NULL; 29 | __u32 proto, nh_off; 30 | struct ethhdr *eth = data; 31 | __u8 key[6] = {0}; 32 | 33 | nh_off = sizeof(struct ethhdr); 34 | if (data + nh_off > data_end) { 35 | return XDP_DROP; 36 | } 37 | 38 | proto = eth->h_proto; 39 | if (proto == BE_ETH_P_IP) { 40 | __builtin_memcpy(key, eth->h_source, 6); 41 | lookup_res = bpf_map_lookup_elem(&map, &key); 42 | if (lookup_res) { 43 | return XDP_PASS; 44 | } else { 45 | return XDP_DROP; 46 | } 47 | } else if (proto == BE_ETH_P_IPV6) { 48 | return XDP_DROP; 49 | } else { 50 | return XDP_PASS; 51 | } 52 | 53 | } 54 | 55 | char _license[] SEC("license") = "GPL"; 56 | -------------------------------------------------------------------------------- /use_cases/l2_acl/src/l2acl_user.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | static const char *__doc__ = "Simple XDP prog doing XDP_PASS\n"; 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include /* depend on kernel-headers installed */ 15 | 16 | #include "../common/common_params.h" 17 | 18 | static const struct option_wrapper long_options[] = { 19 | {{"help", no_argument, NULL, 'h' }, 20 | "Show help", false}, 21 | 22 | {{"dev", required_argument, NULL, 'd' }, 23 | "Operate on device ", "", true}, 24 | 25 | {{"skb-mode", no_argument, NULL, 'S' }, 26 | "Install XDP program in SKB (AKA generic) mode"}, 27 | 28 | {{"native-mode", no_argument, NULL, 'N' }, 29 | "Install XDP program in native mode"}, 30 | 31 | {{"auto-mode", no_argument, NULL, 'A' }, 32 | "Auto-detect SKB or native mode"}, 33 | 34 | {{"force", no_argument, NULL, 'F' }, 35 | "Force install, replacing existing program on interface"}, 36 | 37 | {{"unload", no_argument, NULL, 'U' }, 38 | "Unload XDP program instead of loading"}, 39 | 40 | {{0, 0, NULL, 0 }, NULL, false} 41 | }; 42 | 43 | int load_bpf_object_file__simple(const char *filename) 44 | { 45 | int first_prog_fd = -1; 46 | struct bpf_object *obj; 47 | int err; 48 | 49 | /* Use libbpf for extracting BPF byte-code from BPF-ELF object, and 50 | * loading this into the kernel via bpf-syscall 51 | */ 52 | err = bpf_prog_load(filename, BPF_PROG_TYPE_XDP, &obj, &first_prog_fd); 53 | if (err) { 54 | fprintf(stderr, "ERR: loading BPF-OBJ file(%s) (%d): %s\n", 55 | filename, err, strerror(-err)); 56 | return -1; 57 | } 58 | 59 | /* Simply return the first program file descriptor. 60 | * (Hint: This will get more advanced later) 61 | */ 62 | return first_prog_fd; 63 | } 64 | 65 | static int xdp_link_detach(int ifindex, __u32 xdp_flags) 66 | { 67 | /* Next assignment this will move into ../common/ 68 | * (in more generic version) 69 | */ 70 | int err; 71 | 72 | if ((err = bpf_set_link_xdp_fd(ifindex, -1, xdp_flags)) < 0) { 73 | fprintf(stderr, "ERR: link set xdp unload failed (err=%d):%s\n", 74 | err, strerror(-err)); 75 | return EXIT_FAIL_XDP; 76 | } 77 | return EXIT_OK; 78 | } 79 | 80 | int xdp_link_attach(int ifindex, __u32 xdp_flags, int prog_fd) 81 | { 82 | /* Next assignment this will move into ../common/ */ 83 | int err; 84 | 85 | /* libbpf provide the XDP net_device link-level hook attach helper */ 86 | err = bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags); 87 | if (err == -EEXIST && !(xdp_flags & XDP_FLAGS_UPDATE_IF_NOEXIST)) { 88 | /* Force mode didn't work, probably because a program of the 89 | * opposite type is loaded. Let's unload that and try loading 90 | * again. 91 | */ 92 | 93 | __u32 old_flags = xdp_flags; 94 | 95 | xdp_flags &= ~XDP_FLAGS_MODES; 96 | xdp_flags |= (old_flags & XDP_FLAGS_SKB_MODE) ? XDP_FLAGS_DRV_MODE : XDP_FLAGS_SKB_MODE; 97 | err = bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); 98 | if (!err) 99 | err = bpf_set_link_xdp_fd(ifindex, prog_fd, old_flags); 100 | } 101 | 102 | if (err < 0) { 103 | fprintf(stderr, "ERR: " 104 | "ifindex(%d) link set xdp fd failed (%d): %s\n", 105 | ifindex, -err, strerror(-err)); 106 | 107 | switch (-err) { 108 | case EBUSY: 109 | case EEXIST: 110 | fprintf(stderr, "Hint: XDP already loaded on device" 111 | " use --force to swap/replace\n"); 112 | break; 113 | case EOPNOTSUPP: 114 | fprintf(stderr, "Hint: Native-XDP not supported" 115 | " use --skb-mode or --auto-mode\n"); 116 | break; 117 | default: 118 | break; 119 | } 120 | return EXIT_FAIL_XDP; 121 | } 122 | 123 | return EXIT_OK; 124 | } 125 | 126 | int main(int argc, char **argv) 127 | { 128 | struct bpf_prog_info info = {}; 129 | __u32 info_len = sizeof(info); 130 | char filename[256] = "hxdp_mbm1_TX.o"; 131 | int prog_fd, err; 132 | 133 | struct config cfg = { 134 | .xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE, 135 | .ifindex = -1, 136 | .do_unload = false, 137 | }; 138 | 139 | parse_cmdline_args(argc, argv, long_options, &cfg, __doc__); 140 | /* Required option */ 141 | if (cfg.ifindex == -1) { 142 | fprintf(stderr, "ERR: required option --dev missing\n"); 143 | usage(argv[0], __doc__, long_options, (argc == 1)); 144 | return EXIT_FAIL_OPTION; 145 | } 146 | if (cfg.do_unload) 147 | return xdp_link_detach(cfg.ifindex, cfg.xdp_flags); 148 | 149 | /* Load the BPF-ELF object file and get back first BPF_prog FD */ 150 | prog_fd = load_bpf_object_file__simple(filename); 151 | if (prog_fd <= 0) { 152 | fprintf(stderr, "ERR: loading file: %s\n", filename); 153 | return EXIT_FAIL_BPF; 154 | } 155 | 156 | /* At this point: BPF-prog is (only) loaded by the kernel, and prog_fd 157 | * is our file-descriptor handle. Next step is attaching this FD to a 158 | * kernel hook point, in this case XDP net_device link-level hook. 159 | * Fortunately libbpf have a helper for this: 160 | */ 161 | err = xdp_link_attach(cfg.ifindex, cfg.xdp_flags, prog_fd); 162 | if (err) 163 | return err; 164 | 165 | /* This step is not really needed , BPF-info via bpf-syscall */ 166 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); 167 | if (err) { 168 | fprintf(stderr, "ERR: can't get prog info - %s\n", 169 | strerror(errno)); 170 | return err; 171 | } 172 | 173 | printf("Success: Loading " 174 | "XDP prog name:%s(id:%d) on device:%s(ifindex:%d)\n", 175 | info.name, info.id, cfg.ifname, cfg.ifindex); 176 | return EXIT_OK; 177 | } 178 | -------------------------------------------------------------------------------- /use_cases/nat/.gen/nat.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/nat/.gen/nat.bin -------------------------------------------------------------------------------- /use_cases/nat/.gen/nat_maps.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "offsets": [ 5 | 47, 6 | 83, 7 | 108 8 | ], 9 | "type": 1, 10 | "key_size": 16, 11 | "value_size": 8, 12 | "max_entries": 100000, 13 | "name": "nat_binding_table" 14 | }, 15 | { 16 | "id": 1, 17 | "offsets": [ 18 | 68 19 | ], 20 | "type": 2, 21 | "key_size": 4, 22 | "value_size": 2, 23 | "max_entries": 5000, 24 | "name": "free_ports" 25 | }, 26 | { 27 | "id": 2, 28 | "offsets": [ 29 | 60 30 | ], 31 | "type": 2, 32 | "key_size": 4, 33 | "value_size": 4, 34 | "max_entries": 1, 35 | "name": "last_free_port_idx" 36 | } 37 | ] -------------------------------------------------------------------------------- /use_cases/nat/.gen/nat_readable_mat.txt: -------------------------------------------------------------------------------- 1 | hXDPc-acc Match Action Table: 2 | > size: 6*6B = 36B 3 | > fields: [Pkt(off: 12, len: 16b), Pkt(off: 14, len: 8b) [& 15], Pkt(off: 20, len: 16b) [& 65343], Pkt(off: 23, len: 8b)] 4 | > content: 5 | 0: p0 | [8, 5, 0, 17] | map #0, pc=49, key=([0, 4): Pkt[26, 30), [4, 8): Pkt[30, 34), [8, 10): Pkt[34, 36), [10, 12): Pkt[36, 38), [12, 13): Pkt[23, 24), [13, 16): 0) 6 | 1: p1 | [8, 5, 0, 6] | map #0, pc=49, key=([0, 4): Pkt[26, 30), [4, 8): Pkt[30, 34), [8, 10): Pkt[34, 36), [10, 12): Pkt[36, 38), [12, 13): Pkt[23, 24), [13, 16): 0) 7 | 2: p2 | [8, 5, 0, X] | xdp_drop 8 | 3: p3 | [8, 5, X, X] | xdp_drop 9 | 4: p4 | [8, X, X, X] | xdp_drop 10 | 5: p5 | [X, X, X, X] | xdp_pass 11 | -------------------------------------------------------------------------------- /use_cases/nat/.gen/nat_x2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/nat/.gen/nat_x2.pcap -------------------------------------------------------------------------------- /use_cases/nat/nat.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/nat/nat.o -------------------------------------------------------------------------------- /use_cases/nat/nat.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/nat/nat.pcap -------------------------------------------------------------------------------- /use_cases/nat/nat_map_entries.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "map_id": 0, "key": "84 13 00 00", 4 | "value": "84 13" 5 | }, 6 | { 7 | "map_id": 0, "key": "85 13 00 00", 8 | "value": "85 13" 9 | }, 10 | { 11 | "map_id": 0, "key": "86 13 00 00", 12 | "value": "86 13" 13 | }, 14 | { 15 | "map_id": 0, "key": "87 13 00 00", 16 | "value": "87 13" 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /use_cases/nat/src/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | 3 | XDP_TARGETS := dnat 4 | USER_TARGETS := dnat_user 5 | 6 | LLC ?= llc 7 | CLANG ?= clang 8 | CC := gcc 9 | 10 | LIBBPF_DIR = ../libbpf/src/ 11 | COMMON_DIR = ../common/ 12 | 13 | include $(COMMON_DIR)/common.mk 14 | COMMON_OBJS := $(COMMON_DIR)/common_params.o 15 | -------------------------------------------------------------------------------- /use_cases/nat/src/dnat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "nat_consts.h" 7 | #include "nat_helpers.h" 8 | #include "nat_structs.h" 9 | #include "nat_maps.h" 10 | #include "nat_pckt_parsing.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define bpf_printk(fmt, ...) \ 17 | ({ \ 18 | char ____fmt[] = fmt; \ 19 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 20 | ##__VA_ARGS__); \ 21 | }) 22 | 23 | __attribute__((__always_inline__)) 24 | static inline void connection_table_lookup(struct binding_definition **bind, 25 | struct packet_description *pckt, 26 | void *map) { 27 | 28 | void *p = bpf_map_lookup_elem(map, &pckt->flow); //XXX MAPPA 29 | 30 | if (!p) { 31 | *bind = NULL; 32 | } 33 | 34 | *bind = p; 35 | } 36 | 37 | __attribute__((__always_inline__)) 38 | static inline bool process_l3_headers(struct packet_description *pckt, 39 | struct iphdr *iph) { 40 | //ihl contains len of ipv4 header in 32bit words 41 | if (iph->ihl != 5) { 42 | // if len of ipv4 hdr is not equal to 20bytes that means that header 43 | // contains ip options, and we dont support em 44 | return XDP_DROP; 45 | } 46 | 47 | if (iph->frag_off & PCKT_FRAGMENTED) { 48 | // we drop fragmented packets. 49 | return XDP_DROP; 50 | } 51 | pckt->flow.src = iph->saddr; 52 | pckt->flow.dst = iph->daddr; 53 | 54 | return 0; 55 | } 56 | 57 | __attribute__((__always_inline__)) 58 | static inline int nat_parse_tcp(void *data, void *data_end, 59 | struct packet_description *pckt) { 60 | 61 | struct tcphdr *tcp; 62 | tcp = data; 63 | 64 | 65 | if (tcp + 1 > data_end) { 66 | return XDP_DROP; 67 | } 68 | 69 | /*if (tcp->syn) { 70 | pckt->flags |= F_SYN_SET; 71 | }*/ 72 | 73 | pckt->flow.port16[0] = tcp->source; 74 | pckt->flow.port16[1] = tcp->dest; 75 | return 0; 76 | } 77 | 78 | __attribute__((__always_inline__)) 79 | static inline bool nat_parse_udp(void *data, void *data_end, 80 | struct packet_description *pckt) { 81 | 82 | struct udphdr *udp; 83 | udp = data; 84 | 85 | if (udp + 1 > data_end) { 86 | return XDP_DROP; 87 | } 88 | 89 | pckt->flow.port16[0] = udp->source; 90 | pckt->flow.port16[1] = udp->dest; 91 | return 0; 92 | } 93 | 94 | static __always_inline __u16 csum_fold_helper(__u32 csum) 95 | { 96 | __u32 sum; 97 | sum = (csum >> 16) + (csum & 0xffff); 98 | sum += (sum >> 16); 99 | return ~sum; 100 | } 101 | 102 | __attribute__((__always_inline__)) 103 | static inline int process_packet(void *data, __u64 off, void *data_end, 104 | struct xdp_md *xdp) { 105 | struct binding_definition * nat_binding_entry = NULL; 106 | struct packet_description pckt = {}, ret_pckt = {}; 107 | __u16 * free_port_p = NULL; 108 | __u16 new_ports[2]; 109 | __sum16 * csum_p; 110 | __u32 csum_off; 111 | __u32 l4_hdr_end; 112 | __be32 *new_addr_pck_pointer = NULL; 113 | __be32 new_addr; 114 | __u8 protocol; 115 | int ret; 116 | struct iphdr *ip = data + sizeof(struct eth_hdr); 117 | if (ip+1 > data_end) { 118 | return XDP_DROP; 119 | } 120 | 121 | protocol = ip->protocol; 122 | pckt.flow.proto = protocol; 123 | //bpf_printk("process\n"); 124 | if ((ret = process_l3_headers(&pckt, ip))!= 0) { 125 | return ret; 126 | } 127 | 128 | 129 | void * l4 = (void*)ip + 20; 130 | 131 | //bpf_printk("l3\n"); 132 | if (protocol == IPPROTO_TCP) { 133 | if ((ret = nat_parse_tcp(l4, data_end, &pckt))) { 134 | return ret; 135 | } 136 | } else if (protocol == IPPROTO_UDP) { 137 | if ((ret = nat_parse_udp(l4, data_end, &pckt))) { 138 | return ret; 139 | } 140 | } else { 141 | return XDP_DROP; 142 | } 143 | 144 | /*if ((protocol == IPPROTO_UDP) || !(pckt.flags & F_SYN_SET)) {*/ 145 | connection_table_lookup(&nat_binding_entry, &pckt, &nat_binding_table); 146 | //} 147 | 148 | if (pckt.flow.dst != NAT_EXTERNAL_ADDRESS) { 149 | if (!nat_binding_entry) { 150 | struct binding_definition new_binding_value = {}; 151 | //bpf_printk("nat binding not found\n"); 152 | //retrieve last free port 153 | __u32 zero = 0; 154 | __u32 * last_idx_p = NULL; 155 | 156 | last_idx_p = bpf_map_lookup_elem(&last_free_port_idx, &zero); 157 | 158 | if (!last_idx_p) { 159 | return XDP_DROP; 160 | } 161 | //bpf_printk("last idx %d\n", *last_idx_p); 162 | //check for last_free_port_idx overflow 163 | if (*last_idx_p > MAX_FREE_PORTS_ENTRIES) { 164 | return XDP_DROP; 165 | } 166 | 167 | *last_idx_p += 1; 168 | 169 | //retrieve free_port 170 | free_port_p = bpf_map_lookup_elem(&free_ports, last_idx_p); 171 | 172 | if (!free_port_p) { 173 | return XDP_DROP; 174 | } 175 | //bpf_printk("current free port %d\n", *free_port_p); 176 | new_binding_value.addr = NAT_EXTERNAL_ADDRESS; 177 | new_binding_value.port = *free_port_p; 178 | 179 | if (bpf_map_update_elem(&nat_binding_table, &pckt.flow, &new_binding_value, 0)) { 180 | //bpf_printk("error instering nat binding\n"); 181 | return XDP_DROP; 182 | } 183 | //insert entry for reply packets 184 | ret_pckt.flow.src = pckt.flow.dst; 185 | ret_pckt.flow.dst = NAT_EXTERNAL_ADDRESS; 186 | ret_pckt.flow.port16[0] = pckt.flow.port16[1]; 187 | ret_pckt.flow.port16[1] = *free_port_p; 188 | ret_pckt.flow.proto = pckt.flow.proto; 189 | 190 | new_binding_value.addr = pckt.flow.src; 191 | new_binding_value.port = pckt.flow.port16[0]; 192 | 193 | 194 | //bpf_printk("return bind src %d dst %d\n", ret_pckt.flow.src, ret_pckt.flow.dst); 195 | //bpf_printk("return bind sport %d dport %d\n", ret_pckt.flow.port16[0], ret_pckt.flow.port16[1]); 196 | //bpf_printk("return bind value port %d addr %d\n", new_binding_value.port, new_binding_value.addr); 197 | 198 | if (bpf_map_update_elem(&nat_binding_table, &ret_pckt.flow, &new_binding_value, 0)) { 199 | //bpf_printk("error instering nat reply binding\n"); 200 | return XDP_DROP; 201 | } 202 | //bpf_printk("return binding entry stored\n"); 203 | new_ports[0] = *free_port_p; 204 | } 205 | else { 206 | //bpf_printk("binding entry found\n"); 207 | new_ports[0] = nat_binding_entry->port; 208 | } 209 | 210 | new_addr = NAT_EXTERNAL_ADDRESS; 211 | new_addr_pck_pointer = &ip->saddr; 212 | new_ports[1]= ((__u16 *)l4)[1]; 213 | } 214 | else { 215 | if (!nat_binding_entry) { 216 | //bpf_printk("local non-natted packet. pass"); 217 | return XDP_DROP; 218 | } 219 | //bpf_printk("natted return packet. get new addr and port\n"); 220 | new_ports[0] = ((__u16 *)l4)[0]; 221 | new_ports[1] = nat_binding_entry->port; 222 | new_addr = nat_binding_entry->addr; 223 | new_addr_pck_pointer = &ip->daddr; 224 | } 225 | 226 | //recompute ip csum 227 | ip->check = csum_fold_helper(bpf_csum_diff(new_addr_pck_pointer, sizeof(__be32), &new_addr, sizeof(__be32), ~(ip->check))); 228 | 229 | //recompute l4 csum 230 | if (ip->protocol == IPPROTO_UDP) { 231 | csum_off = 40; 232 | l4_hdr_end = 2; 233 | } 234 | else if (ip->protocol == IPPROTO_TCP) { 235 | csum_off = 52; 236 | l4_hdr_end = 4; 237 | } 238 | else { 239 | return XDP_DROP; 240 | } 241 | 242 | csum_p = (__sum16 *) ((__u8 *)data + csum_off); 243 | 244 | if (data + csum_off + l4_hdr_end > data_end) { 245 | return XDP_DROP; 246 | } 247 | 248 | *csum_p = csum_fold_helper(bpf_csum_diff((__be32*) l4, sizeof(__be32), (__be32 *)new_ports, sizeof(__be32), ~(*(__u16 *)csum_p))); 249 | 250 | *csum_p = csum_fold_helper(bpf_csum_diff(new_addr_pck_pointer, sizeof(__be32), &new_addr, sizeof(__be32), ~(*(__u16 *)csum_p))); 251 | 252 | //change source port 253 | __builtin_memcpy(l4, &new_ports[0], 4); 254 | __builtin_memcpy((__u8 *) new_addr_pck_pointer, &new_addr , 4); 255 | //bpf_printk("ready to TX\n"); 256 | return XDP_TX; 257 | } 258 | 259 | SEC("xdp") 260 | int nat_ingress(struct xdp_md *ctx) { 261 | void *data = (void *)(long)ctx->data; 262 | void *data_end = (void *)(long)ctx->data_end; 263 | struct eth_hdr *eth = data; 264 | __u32 eth_proto; 265 | __u32 nh_off; 266 | nh_off = sizeof(struct eth_hdr); 267 | 268 | //bpf_printk("GOT PACKET\n"); 269 | if (data + nh_off > data_end) { 270 | // bogus packet, len less than minimum ethernet frame size 271 | return XDP_DROP; 272 | } 273 | 274 | eth_proto = eth->eth_proto; 275 | if (eth_proto == BE_ETH_P_IP) { 276 | return process_packet(data, nh_off, data_end, ctx); 277 | } else { 278 | return XDP_PASS; 279 | } 280 | } 281 | 282 | char _license[] SEC("license") = "GPL"; 283 | -------------------------------------------------------------------------------- /use_cases/nat/src/dnat_user.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | static const char *__doc__ = "Simple XDP prog doing XDP_PASS\n"; 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include /* depend on kernel-headers installed */ 15 | 16 | #include "../common/common_params.h" 17 | 18 | static const struct option_wrapper long_options[] = { 19 | {{"help", no_argument, NULL, 'h' }, 20 | "Show help", false}, 21 | 22 | {{"dev", required_argument, NULL, 'd' }, 23 | "Operate on device ", "", true}, 24 | 25 | {{"skb-mode", no_argument, NULL, 'S' }, 26 | "Install XDP program in SKB (AKA generic) mode"}, 27 | 28 | {{"native-mode", no_argument, NULL, 'N' }, 29 | "Install XDP program in native mode"}, 30 | 31 | {{"auto-mode", no_argument, NULL, 'A' }, 32 | "Auto-detect SKB or native mode"}, 33 | 34 | {{"force", no_argument, NULL, 'F' }, 35 | "Force install, replacing existing program on interface"}, 36 | 37 | {{"unload", no_argument, NULL, 'U' }, 38 | "Unload XDP program instead of loading"}, 39 | 40 | {{0, 0, NULL, 0 }, NULL, false} 41 | }; 42 | 43 | int load_bpf_object_file__simple(const char *filename) 44 | { 45 | int first_prog_fd = -1; 46 | struct bpf_object *obj; 47 | int err; 48 | 49 | /* Use libbpf for extracting BPF byte-code from BPF-ELF object, and 50 | * loading this into the kernel via bpf-syscall 51 | */ 52 | err = bpf_prog_load(filename, BPF_PROG_TYPE_XDP, &obj, &first_prog_fd); 53 | if (err) { 54 | fprintf(stderr, "ERR: loading BPF-OBJ file(%s) (%d): %s\n", 55 | filename, err, strerror(-err)); 56 | return -1; 57 | } 58 | 59 | /* Simply return the first program file descriptor. 60 | * (Hint: This will get more advanced later) 61 | */ 62 | return first_prog_fd; 63 | } 64 | 65 | static int xdp_link_detach(int ifindex, __u32 xdp_flags) 66 | { 67 | /* Next assignment this will move into ../common/ 68 | * (in more generic version) 69 | */ 70 | int err; 71 | 72 | if ((err = bpf_set_link_xdp_fd(ifindex, -1, xdp_flags)) < 0) { 73 | fprintf(stderr, "ERR: link set xdp unload failed (err=%d):%s\n", 74 | err, strerror(-err)); 75 | return EXIT_FAIL_XDP; 76 | } 77 | return EXIT_OK; 78 | } 79 | 80 | int xdp_link_attach(int ifindex, __u32 xdp_flags, int prog_fd) 81 | { 82 | /* Next assignment this will move into ../common/ */ 83 | int err; 84 | 85 | /* libbpf provide the XDP net_device link-level hook attach helper */ 86 | err = bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags); 87 | if (err == -EEXIST && !(xdp_flags & XDP_FLAGS_UPDATE_IF_NOEXIST)) { 88 | /* Force mode didn't work, probably because a program of the 89 | * opposite type is loaded. Let's unload that and try loading 90 | * again. 91 | */ 92 | 93 | __u32 old_flags = xdp_flags; 94 | 95 | xdp_flags &= ~XDP_FLAGS_MODES; 96 | xdp_flags |= (old_flags & XDP_FLAGS_SKB_MODE) ? XDP_FLAGS_DRV_MODE : XDP_FLAGS_SKB_MODE; 97 | err = bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); 98 | if (!err) 99 | err = bpf_set_link_xdp_fd(ifindex, prog_fd, old_flags); 100 | } 101 | 102 | if (err < 0) { 103 | fprintf(stderr, "ERR: " 104 | "ifindex(%d) link set xdp fd failed (%d): %s\n", 105 | ifindex, -err, strerror(-err)); 106 | 107 | switch (-err) { 108 | case EBUSY: 109 | case EEXIST: 110 | fprintf(stderr, "Hint: XDP already loaded on device" 111 | " use --force to swap/replace\n"); 112 | break; 113 | case EOPNOTSUPP: 114 | fprintf(stderr, "Hint: Native-XDP not supported" 115 | " use --skb-mode or --auto-mode\n"); 116 | break; 117 | default: 118 | break; 119 | } 120 | return EXIT_FAIL_XDP; 121 | } 122 | 123 | return EXIT_OK; 124 | } 125 | 126 | int main(int argc, char **argv) 127 | { 128 | struct bpf_prog_info info = {}; 129 | __u32 info_len = sizeof(info); 130 | char filename[256] = "hxdp_mbm1_TX.o"; 131 | int prog_fd, err; 132 | 133 | struct config cfg = { 134 | .xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE, 135 | .ifindex = -1, 136 | .do_unload = false, 137 | }; 138 | 139 | parse_cmdline_args(argc, argv, long_options, &cfg, __doc__); 140 | /* Required option */ 141 | if (cfg.ifindex == -1) { 142 | fprintf(stderr, "ERR: required option --dev missing\n"); 143 | usage(argv[0], __doc__, long_options, (argc == 1)); 144 | return EXIT_FAIL_OPTION; 145 | } 146 | if (cfg.do_unload) 147 | return xdp_link_detach(cfg.ifindex, cfg.xdp_flags); 148 | 149 | /* Load the BPF-ELF object file and get back first BPF_prog FD */ 150 | prog_fd = load_bpf_object_file__simple(filename); 151 | if (prog_fd <= 0) { 152 | fprintf(stderr, "ERR: loading file: %s\n", filename); 153 | return EXIT_FAIL_BPF; 154 | } 155 | 156 | /* At this point: BPF-prog is (only) loaded by the kernel, and prog_fd 157 | * is our file-descriptor handle. Next step is attaching this FD to a 158 | * kernel hook point, in this case XDP net_device link-level hook. 159 | * Fortunately libbpf have a helper for this: 160 | */ 161 | err = xdp_link_attach(cfg.ifindex, cfg.xdp_flags, prog_fd); 162 | if (err) 163 | return err; 164 | 165 | /* This step is not really needed , BPF-info via bpf-syscall */ 166 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); 167 | if (err) { 168 | fprintf(stderr, "ERR: can't get prog info - %s\n", 169 | strerror(errno)); 170 | return err; 171 | } 172 | 173 | printf("Success: Loading " 174 | "XDP prog name:%s(id:%d) on device:%s(ifindex:%d)\n", 175 | info.name, info.id, cfg.ifname, cfg.ifindex); 176 | return EXIT_OK; 177 | } 178 | -------------------------------------------------------------------------------- /use_cases/nat/src/nat_consts.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018-present, Facebook, Inc. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License along 13 | * with this program; if not, write to the Free Software Foundation, Inc., 14 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 15 | */ 16 | 17 | #ifndef __NAT_CONSTS_H 18 | #define __NAT_CONSTS_H 19 | /* 20 | * This file contains definition of all balancer specific constants 21 | */ 22 | 23 | // we dont want to do htons for each packet, so this is ETH_P_IPV6 and 24 | // ETH_P_IP in be format 25 | #define BE_ETH_P_IP 8 26 | 27 | 28 | // 3FFF mask covers more fragments flag and fragment offset field. 29 | // 65343 = 3FFF in BigEndian 30 | #define PCKT_FRAGMENTED 65343 31 | 32 | #define F_SYN_SET (1 << 1) 33 | #define NO_FLAGS 0 34 | #define DEFAULT_MAX_ENTRIES_NAT_TABLE 100000 35 | #define MAX_FREE_PORTS_ENTRIES 5000 36 | #define NAT_EXTERNAL_ADDRESS 0xcafebabe 37 | #define FURTHER_PROCESSING -1 38 | #endif // of __BALANCER_CONSTS_H 39 | -------------------------------------------------------------------------------- /use_cases/nat/src/nat_helpers.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018-present, Facebook, Inc. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License along 13 | * with this program; if not, write to the Free Software Foundation, Inc., 14 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 15 | */ 16 | 17 | #ifndef __NAT_HELPERS 18 | #define __NAT_HELPERS 19 | /* 20 | * This file contains common used routines. such as csum helpers etc 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "nat_consts.h" 29 | #include "nat_structs.h" 30 | #include "nat_maps.h" 31 | //#include "csum_helpers.h" 32 | 33 | 34 | #include 35 | #include 36 | #define bpf_printk(fmt, ...) \ 37 | ({ \ 38 | char ____fmt[] = fmt; \ 39 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 40 | ##__VA_ARGS__); \ 41 | }) 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /use_cases/nat/src/nat_maps.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018-present, Facebook, Inc. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License along 13 | * with this program; if not, write to the Free Software Foundation, Inc., 14 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 15 | */ 16 | 17 | #ifndef __NAT_MAPS_H 18 | #define __NAT_MAPS_H 19 | 20 | /* 21 | * This file contains definition of all maps which has been used by balancer 22 | */ 23 | 24 | #include 25 | #include 26 | #include "nat_consts.h" 27 | #include "nat_structs.h" 28 | 29 | // nat binding tables 30 | struct bpf_map_def SEC("maps") nat_binding_table = { 31 | .type = BPF_MAP_TYPE_HASH, 32 | .key_size = sizeof(struct flow_key), 33 | .value_size = sizeof(struct binding_definition), 34 | .max_entries = DEFAULT_MAX_ENTRIES_NAT_TABLE, 35 | .map_flags = NO_FLAGS, 36 | }; 37 | //BPF_ANNOTATE_KV_PAIR(nat_binding_table, struct flow_key, struct binding_definition); 38 | 39 | // map which contains 1 elemnent with the last idx for the free_port array 40 | struct bpf_map_def SEC("maps") last_free_port_idx = { 41 | .type = BPF_MAP_TYPE_ARRAY, 42 | .key_size = sizeof(__u32), 43 | .value_size = sizeof(__u32), 44 | .max_entries = 1, 45 | .map_flags = NO_FLAGS, 46 | }; 47 | //BPF_ANNOTATE_KV_PAIR(last_free_port_idx, __u32, __u32); 48 | 49 | // map which contains the free_port list 50 | struct bpf_map_def SEC("maps") free_ports = { 51 | .type = BPF_MAP_TYPE_ARRAY, 52 | .key_size = sizeof(__u32), 53 | .value_size = sizeof(__u16), 54 | .max_entries = MAX_FREE_PORTS_ENTRIES, 55 | .map_flags = NO_FLAGS, 56 | }; 57 | //BPF_ANNOTATE_KV_PAIR(free_ports, __u32, __u16); 58 | 59 | #endif // of _NAT_MAPS 60 | -------------------------------------------------------------------------------- /use_cases/nat/src/nat_pckt_parsing.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018-present, Facebook, Inc. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License along 13 | * with this program; if not, write to the Free Software Foundation, Inc., 14 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 15 | */ 16 | 17 | #ifndef __NAT_PCKT_PARSING_H 18 | #define __NAT_PCKT_PARSING_H 19 | 20 | /* 21 | * This file contains generic packet parsing routines (e.g. tcp/udp headers 22 | * parsing etc) 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include "nat_consts.h" 39 | 40 | struct eth_hdr { 41 | unsigned char eth_dest[ETH_ALEN]; 42 | unsigned char eth_source[ETH_ALEN]; 43 | unsigned short eth_proto; 44 | }; 45 | 46 | 47 | __attribute__((__always_inline__)) 48 | static inline __u64 calc_offset(bool is_ipv6, bool is_icmp) { 49 | __u64 off = sizeof(struct eth_hdr); 50 | if (is_ipv6) { 51 | off += sizeof(struct ipv6hdr); 52 | if (is_icmp) { 53 | off += (sizeof(struct icmp6hdr) + sizeof(struct ipv6hdr)); 54 | } 55 | } else { 56 | off += sizeof(struct iphdr); 57 | if (is_icmp) { 58 | off += (sizeof(struct icmphdr) + sizeof(struct iphdr)); 59 | } 60 | } 61 | return off; 62 | } 63 | 64 | 65 | 66 | #endif // of __PCKT_PARSING_H 67 | -------------------------------------------------------------------------------- /use_cases/nat/src/nat_structs.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018-present, Facebook, Inc. 2 | * 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; version 2 of the License. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License along 13 | * with this program; if not, write to the Free Software Foundation, Inc., 14 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 15 | */ 16 | 17 | #ifndef __NAT_STRUCTS_H 18 | #define __NAT_STRUCTS_H 19 | 20 | 21 | // flow metadata 22 | struct flow_key { 23 | __be32 src; 24 | __be32 dst; 25 | __u16 port16[2]; 26 | __u8 proto; 27 | }; 28 | 29 | // client's packet metadata 30 | struct packet_description { 31 | struct flow_key flow; 32 | __u8 flags;}; 33 | // dscp / ToS value in client's packet 34 | // __u32 real_index; 35 | //__u8 tos; 36 | //}; 37 | 38 | 39 | struct binding_definition { 40 | __be32 addr; 41 | __u16 port; 42 | }; 43 | 44 | 45 | #endif // of _BALANCER_STRUCTS 46 | -------------------------------------------------------------------------------- /use_cases/suricata/.gen/match_action_table_readable.txt: -------------------------------------------------------------------------------- 1 | Orthogonal branch 2 | 3 | Orthogonal branch 4 | 5 | Orthogonal branch 6 | 7 | Orthogonal branch 8 | 9 | Orthogonal branch 10 | 11 | Orthogonal branch 12 | 13 | Orthogonal branch 14 | 15 | Orthogonal branch 16 | 17 | Orthogonal branch 18 | 19 | Orthogonal branch 20 | 21 | Orthogonal branch 22 | 23 | Orthogonal branch 24 | 25 | Orthogonal branch 26 | 27 | Orthogonal branch 28 | 29 | Orthogonal branch 30 | 31 | Orthogonal branch 32 | 33 | Orthogonal branch 34 | 35 | Orthogonal branch 36 | 37 | Orthogonal branch 38 | 39 | Orthogonal branch 40 | 41 | Orthogonal branch 42 | 43 | Orthogonal branch 44 | 45 | Orthogonal branch 46 | 47 | Orthogonal branch 48 | 49 | Orthogonal branch 50 | 51 | Orthogonal branch 52 | 53 | Orthogonal branch 54 | 55 | Orthogonal branch 56 | 57 | Orthogonal branch 58 | 59 | Orthogonal branch 60 | 61 | Orthogonal branch 62 | 63 | Orthogonal branch 64 | 65 | Orthogonal branch 66 | 67 | Orthogonal branch 68 | 69 | Orthogonal branch 70 | 71 | Orthogonal branch 72 | 73 | Orthogonal branch 74 | 75 | hXDPc-acc Match Action Table: 76 | > size: 49*12B = 588B 77 | > fields: [Pkt(off: 12, len: 16b), Pkt(off: 16, len: 16b) [& 65535], Pkt(off: 20, len: 8b), Pkt(off: 20, len: 16b) [& 65535], Pkt(off: 23, len: 8b), Pkt(off: 24, len: 8b), Pkt(off: 27, len: 8b), Pkt(off: 28, len: 8b), Pkt(off: 31, len: 8b)] 78 | > content: 79 | 0: p0 | [43144, 43144, X, 56710, X, X, X, 17, X] | map #1, pc=126 80 | 1: p1 | [43144, 43144, X, 56710, X, X, X, 6, X] | map #1, pc=126 81 | 2: p2 | [43144, 43144, X, 56710, X, X, X, X, X] | xdp_pass 82 | 3: p3 | [43144, 43144, X, 8, X, X, X, X, 6] | map #0, pc=86 83 | 4: p4 | [43144, 43144, X, 8, X, X, X, X, 17] | map #0, pc=86 84 | 5: p5 | [43144, 43144, X, 8, X, X, X, X, X] | map #0, pc=86 85 | 6: p6 | [43144, 43144, X, X, X, X, X, X, X] | xdp_pass 86 | 7: p7 | [43144, 129, X, 56710, X, X, X, 17, X] | map #1, pc=126 87 | 8: p8 | [43144, 129, X, 56710, X, X, X, 6, X] | map #1, pc=126 88 | 9: p9 | [43144, 129, X, 56710, X, X, X, X, X] | xdp_pass 89 | 10: p10 | [43144, 129, X, 8, X, X, X, X, 6] | map #0, pc=86 90 | 11: p11 | [43144, 129, X, 8, X, X, X, X, 17] | map #0, pc=86 91 | 12: p12 | [43144, 129, X, 8, X, X, X, X, X] | map #0, pc=86 92 | 13: p13 | [43144, 129, X, X, X, X, X, X, X] | xdp_pass 93 | 14: p14 | [43144, 56710, X, X, X, 17, X, X, X] | map #1, pc=126 94 | 15: p15 | [43144, 56710, X, X, X, 6, X, X, X] | map #1, pc=126 95 | 16: p16 | [43144, 56710, X, X, X, X, X, X, X] | xdp_pass 96 | 17: p17 | [43144, 8, X, X, X, X, 6, X, X] | map #0, pc=86 97 | 18: p18 | [43144, 8, X, X, X, X, 17, X, X] | map #0, pc=86 98 | 19: p19 | [43144, 8, X, X, X, X, X, X, X] | map #0, pc=86 99 | 20: p20 | [43144, X, X, X, X, X, X, X, X] | xdp_pass 100 | 21: p21 | [129, 43144, X, 56710, X, X, X, 17, X] | map #1, pc=126 101 | 22: p22 | [129, 43144, X, 56710, X, X, X, 6, X] | map #1, pc=126 102 | 23: p23 | [129, 43144, X, 56710, X, X, X, X, X] | xdp_pass 103 | 24: p24 | [129, 43144, X, 8, X, X, X, X, 6] | map #0, pc=86 104 | 25: p25 | [129, 43144, X, 8, X, X, X, X, 17] | map #0, pc=86 105 | 26: p26 | [129, 43144, X, 8, X, X, X, X, X] | map #0, pc=86 106 | 27: p27 | [129, 43144, X, X, X, X, X, X, X] | xdp_pass 107 | 28: p28 | [129, 129, X, 56710, X, X, X, 17, X] | map #1, pc=126 108 | 29: p29 | [129, 129, X, 56710, X, X, X, 6, X] | map #1, pc=126 109 | 30: p30 | [129, 129, X, 56710, X, X, X, X, X] | xdp_pass 110 | 31: p31 | [129, 129, X, 8, X, X, X, X, 6] | map #0, pc=86 111 | 32: p32 | [129, 129, X, 8, X, X, X, X, 17] | map #0, pc=86 112 | 33: p33 | [129, 129, X, 8, X, X, X, X, X] | map #0, pc=86 113 | 34: p34 | [129, 129, X, X, X, X, X, X, X] | xdp_pass 114 | 35: p35 | [129, 56710, X, X, X, 17, X, X, X] | map #1, pc=126 115 | 36: p36 | [129, 56710, X, X, X, 6, X, X, X] | map #1, pc=126 116 | 37: p37 | [129, 56710, X, X, X, X, X, X, X] | xdp_pass 117 | 38: p38 | [129, 8, X, X, X, X, 6, X, X] | map #0, pc=86 118 | 39: p39 | [129, 8, X, X, X, X, 17, X, X] | map #0, pc=86 119 | 40: p40 | [129, 8, X, X, X, X, X, X, X] | map #0, pc=86 120 | 41: p41 | [129, X, X, X, X, X, X, X, X] | xdp_pass 121 | 42: p42 | [56710, X, 17, X, X, X, X, X, X] | map #1, pc=126 122 | 43: p43 | [56710, X, 6, X, X, X, X, X, X] | map #1, pc=126 123 | 44: p44 | [56710, X, X, X, X, X, X, X, X] | xdp_pass 124 | 45: p45 | [8, X, X, X, 6, X, X, X, X] | map #0, pc=86 125 | 46: p46 | [8, X, X, X, 17, X, X, X, X] | map #0, pc=86 126 | 47: p47 | [8, X, X, X, X, X, X, X, X] | map #0, pc=86 127 | 48: p48 | [X, X, X, X, X, X, X, X, X] | xdp_pass 128 | -------------------------------------------------------------------------------- /use_cases/suricata/.gen/suricata.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/suricata/.gen/suricata.bin -------------------------------------------------------------------------------- /use_cases/suricata/.gen/suricata_maps.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "offsets": [ 5 | 84 6 | ], 7 | "type": 5, 8 | "key_size": 16, 9 | "value_size": 16, 10 | "max_entries": 32768, 11 | "name": "flow_table_v4" 12 | }, 13 | { 14 | "id": 1, 15 | "offsets": [ 16 | 124 17 | ], 18 | "type": 5, 19 | "key_size": 40, 20 | "value_size": 16, 21 | "max_entries": 32768, 22 | "name": "flow_table_v6" 23 | } 24 | ] -------------------------------------------------------------------------------- /use_cases/suricata/suricata.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/suricata/suricata.o -------------------------------------------------------------------------------- /use_cases/suricata/suricata.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/suricata/suricata.pcap -------------------------------------------------------------------------------- /use_cases/suricata/suricata_map_entries.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "comment": "ipv6|udp|no-vlan", 4 | "map_id": 1, "key": "11 11 00 00 00 00 00 00 00 00 00 00 00 00 11 11 22 22 00 00 00 00 00 00 00 00 00 00 00 00 22 22 aa aa bb bb 00 00 00 00", 5 | "value": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 6 | }, 7 | { 8 | "comment": "ipv6|tcp|no-vlan", 9 | "map_id": 1, "key": "11 11 00 00 00 00 00 00 00 00 00 00 00 00 11 11 22 22 00 00 00 00 00 00 00 00 00 00 00 00 22 22 aa aa bb bb 01 00 00 00", 10 | "value": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 11 | }, 12 | { 13 | "comment": "ipv4|udp|no-vlan", 14 | "map_id": 0, "key": "01 01 01 01 02 02 02 02 aa aa bb bb 00 00 00 00", 15 | "value": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 16 | }, 17 | { 18 | "comment": "ipv4|tcp|no-vlan", 19 | "map_id": 0, "key": "01 01 01 01 02 02 02 02 aa aa bb bb 01 00 00 00", 20 | "value": "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /use_cases/xdp_router/.gen/match_action_table_readable.txt: -------------------------------------------------------------------------------- 1 | hXDPc-acc Match Action Table: 2 | > size: 9*4B = 36B 3 | > fields: [Pkt(off: 12, len: 16b) [AluOps.le None], Pkt(off: 16, len: 16b) [& 65535]] 4 | > content: 5 | 0: p0 | [43144, 1544] | xdp_pass 6 | 1: p1 | [43144, 8] | map #3, pc=38, key=([0, 4): Pkt[34, 38)) 7 | 2: p2 | [43144, X] | xdp_drop 8 | 3: p3 | [129, 1544] | xdp_pass 9 | 4: p4 | [129, 8] | map #3, pc=38, key=([0, 4): Pkt[34, 38)) 10 | 5: p5 | [129, X] | xdp_drop 11 | 6: p6 | [1544, X] | xdp_pass 12 | 7: p7 | [8, X] | map #3, pc=38, key=([0, 4): Pkt[30, 34)) 13 | 8: p8 | [X, X] | xdp_drop 14 | -------------------------------------------------------------------------------- /use_cases/xdp_router/.gen/router.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/xdp_router/.gen/router.bin -------------------------------------------------------------------------------- /use_cases/xdp_router/.gen/router_maps.json: -------------------------------------------------------------------------------- 1 | [{"offsets": [62], "type": 11, "key_size": 8, "value_size": 32, "max_entries": 50}, 2 | {"offsets": [107], "type": 14, "key_size": 4, "value_size": 4, "max_entries": 100}, 3 | {"offsets": [36], "type": 1, "key_size": 4, "value_size": 32, "max_entries": 50}, 4 | {"offsets": [69, 80], "type": 1, "key_size": 4, "value_size": 8, "max_entries": 50}, 5 | {"offsets": [100], "type": 6, "key_size": 4, "value_size": 8, "max_entries": 256}] -------------------------------------------------------------------------------- /use_cases/xdp_router/.gen/router_x2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/xdp_router/.gen/router_x2.pcap -------------------------------------------------------------------------------- /use_cases/xdp_router/router.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/xdp_router/router.o -------------------------------------------------------------------------------- /use_cases/xdp_router/router.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/xdp_router/router.pcap -------------------------------------------------------------------------------- /use_cases/xdp_router/router_map_entries.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "map_id": 0, "key": "00 00 00 18 0a 01 02 00", 4 | "value": "00 00 00 20 aa bb cc dd ee ff 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01" 5 | }, 6 | { 7 | "map_id": 2, "key": "0a 01 02 04", 8 | "value": "cc cc cc cc cc cc 00 00" 9 | }, 10 | { 11 | "map_id": 2, "key": "0a 01 02 03", 12 | "value": "cc cc cc cc cc cc 00 00" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /use_cases/xdp_tunnel/.gen/tun.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/xdp_tunnel/.gen/tun.bin -------------------------------------------------------------------------------- /use_cases/xdp_tunnel/.gen/tun_maps.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "offsets": [ 5 | 157, 6 | 273 7 | ], 8 | "type": 6, 9 | "key_size": 4, 10 | "value_size": 8, 11 | "max_entries": 256, 12 | "name": "rxcnt" 13 | }, 14 | { 15 | "id": 1, 16 | "offsets": [ 17 | 60, 18 | 184 19 | ], 20 | "type": 1, 21 | "key_size": 24, 22 | "value_size": 40, 23 | "max_entries": 256, 24 | "name": "vip2tnl" 25 | } 26 | ] -------------------------------------------------------------------------------- /use_cases/xdp_tunnel/.gen/tun_readable_mat.txt: -------------------------------------------------------------------------------- 1 | hXDPc-acc Match Action Table: 2 | > size: 7*4B = 28B 3 | > fields: [Pkt(off: 12, len: 16b), Pkt(off: 20, len: 8b), Pkt(off: 23, len: 8b)] 4 | > content: 5 | 0: p0 | [56710, 17, X] | map #1, pc=186 6 | 1: p1 | [56710, 6, X] | map #1, pc=186 7 | 2: p2 | [56710, X, X] | map #1, pc=186 8 | 3: p3 | [8, X, 17] | map #1, pc=62 9 | 4: p4 | [8, X, 6] | map #1, pc=62 10 | 5: p5 | [8, X, X] | map #1, pc=62 11 | 6: p6 | [X, X, X] | xdp_pass 12 | -------------------------------------------------------------------------------- /use_cases/xdp_tunnel/.gen/tun_x2.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/xdp_tunnel/.gen/tun_x2.pcap -------------------------------------------------------------------------------- /use_cases/xdp_tunnel/tun.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/xdp_tunnel/tun.o -------------------------------------------------------------------------------- /use_cases/xdp_tunnel/tun.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/axbryd/warp-artifacts/70a62666f139662f31baad436c0205a9667ebea5/use_cases/xdp_tunnel/tun.pcap -------------------------------------------------------------------------------- /use_cases/xdp_tunnel/tun_map_entries.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "map_id": 1, "key": "11 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00 cc dd 02 00 06 00 00 00", 4 | "value": "ee ee ee ee 00 00 00 00 00 00 00 00 00 00 00 00 cc cc cc cc 00 00 00 00 00 00 00 00 00 00 00 00 02 00 aa bb cc dd ee ff" 5 | }, 6 | { 7 | "map_id": 1, "key": "aa bb cc dd ee ff 11 22 33 44 55 66 77 88 99 00 aa bb 0a 00 06 00 00 00", 8 | "value": "11 22 33 44 00 00 00 00 00 00 00 00 00 00 00 00 dd cc bb aa 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 aa bb cc dd ee ff" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /warp_compiler.sh: -------------------------------------------------------------------------------- 1 | curl --fail --location --request POST '18.213.18.68:3200/compile' --form 'file=@"'$1'"' --form 'secname="'$2'"' > $1_MAT.json 2 | if [ $? -ne 0 ]; then 3 | echo "-----------" 4 | echo "An Error occurred" 5 | else 6 | echo "-----------" 7 | echo "Match-action table saved in $1_MAT.json" 8 | fi 9 | --------------------------------------------------------------------------------