├── .gitignore ├── .gitmodules ├── COPYING ├── README.rst ├── headers ├── bpf_endian.h ├── bpf_helpers.h ├── jhash.h └── perf-sys.h ├── l4lb ├── Makefile ├── README.rst ├── bpftool_utils.py ├── destination_samples │ ├── 128_destinations.csv │ ├── 256_destinations.csv │ ├── 32_destinations.csv │ └── 512_destinations.csv ├── l4lb_map.py ├── l4lb_stats.py └── l4lb_xdp.c ├── programmable_rss ├── Makefile ├── README.rst ├── rss_common.h ├── rss_kern.c ├── rss_user.c └── traffic_IPIP.pcap └── xdpdump ├── Makefile ├── README.rst ├── xdpdump_common.h ├── xdpdump_kern.c └── xdpdump_user.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.ll 2 | *.o 3 | *.pyc 4 | *.swp 5 | rss 6 | xdpdump 7 | tmp_bpftool.txt 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libbpf"] 2 | path = libbpf 3 | url = https://github.com/libbpf/libbpf.git 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The BSD 2-Clause License 2 | 3 | Copyright (C) 2018 Netronome Systems, Inc. 4 | 5 | Redistribution and use in source and binary forms, with or 6 | without modification, are permitted provided that the following 7 | conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above 10 | copyright notice, this list of conditions and the following 11 | disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following 15 | disclaimer in the documentation and/or other materials 16 | provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | 30 | GNU GENERAL PUBLIC LICENSE 31 | Version 2, June 1991 32 | 33 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 34 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 35 | Everyone is permitted to copy and distribute verbatim copies 36 | of this license document, but changing it is not allowed. 37 | 38 | Preamble 39 | 40 | The licenses for most software are designed to take away your 41 | freedom to share and change it. By contrast, the GNU General Public 42 | License is intended to guarantee your freedom to share and change free 43 | software--to make sure the software is free for all its users. This 44 | General Public License applies to most of the Free Software 45 | Foundation's software and to any other program whose authors commit to 46 | using it. (Some other Free Software Foundation software is covered by 47 | the GNU Lesser General Public License instead.) You can apply it to 48 | your programs, too. 49 | 50 | When we speak of free software, we are referring to freedom, not 51 | price. Our General Public Licenses are designed to make sure that you 52 | have the freedom to distribute copies of free software (and charge for 53 | this service if you wish), that you receive source code or can get it 54 | if you want it, that you can change the software or use pieces of it 55 | in new free programs; and that you know you can do these things. 56 | 57 | To protect your rights, we need to make restrictions that forbid 58 | anyone to deny you these rights or to ask you to surrender the rights. 59 | These restrictions translate to certain responsibilities for you if you 60 | distribute copies of the software, or if you modify it. 61 | 62 | For example, if you distribute copies of such a program, whether 63 | gratis or for a fee, you must give the recipients all the rights that 64 | you have. You must make sure that they, too, receive or can get the 65 | source code. And you must show them these terms so they know their 66 | rights. 67 | 68 | We protect your rights with two steps: (1) copyright the software, and 69 | (2) offer you this license which gives you legal permission to copy, 70 | distribute and/or modify the software. 71 | 72 | Also, for each author's protection and ours, we want to make certain 73 | that everyone understands that there is no warranty for this free 74 | software. If the software is modified by someone else and passed on, we 75 | want its recipients to know that what they have is not the original, so 76 | that any problems introduced by others will not reflect on the original 77 | authors' reputations. 78 | 79 | Finally, any free program is threatened constantly by software 80 | patents. We wish to avoid the danger that redistributors of a free 81 | program will individually obtain patent licenses, in effect making the 82 | program proprietary. To prevent this, we have made it clear that any 83 | patent must be licensed for everyone's free use or not licensed at all. 84 | 85 | The precise terms and conditions for copying, distribution and 86 | modification follow. 87 | 88 | GNU GENERAL PUBLIC LICENSE 89 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 90 | 91 | 0. This License applies to any program or other work which contains 92 | a notice placed by the copyright holder saying it may be distributed 93 | under the terms of this General Public License. The "Program", below, 94 | refers to any such program or work, and a "work based on the Program" 95 | means either the Program or any derivative work under copyright law: 96 | that is to say, a work containing the Program or a portion of it, 97 | either verbatim or with modifications and/or translated into another 98 | language. (Hereinafter, translation is included without limitation in 99 | the term "modification".) Each licensee is addressed as "you". 100 | 101 | Activities other than copying, distribution and modification are not 102 | covered by this License; they are outside its scope. The act of 103 | running the Program is not restricted, and the output from the Program 104 | is covered only if its contents constitute a work based on the 105 | Program (independent of having been made by running the Program). 106 | Whether that is true depends on what the Program does. 107 | 108 | 1. You may copy and distribute verbatim copies of the Program's 109 | source code as you receive it, in any medium, provided that you 110 | conspicuously and appropriately publish on each copy an appropriate 111 | copyright notice and disclaimer of warranty; keep intact all the 112 | notices that refer to this License and to the absence of any warranty; 113 | and give any other recipients of the Program a copy of this License 114 | along with the Program. 115 | 116 | You may charge a fee for the physical act of transferring a copy, and 117 | you may at your option offer warranty protection in exchange for a fee. 118 | 119 | 2. You may modify your copy or copies of the Program or any portion 120 | of it, thus forming a work based on the Program, and copy and 121 | distribute such modifications or work under the terms of Section 1 122 | above, provided that you also meet all of these conditions: 123 | 124 | a) You must cause the modified files to carry prominent notices 125 | stating that you changed the files and the date of any change. 126 | 127 | b) You must cause any work that you distribute or publish, that in 128 | whole or in part contains or is derived from the Program or any 129 | part thereof, to be licensed as a whole at no charge to all third 130 | parties under the terms of this License. 131 | 132 | c) If the modified program normally reads commands interactively 133 | when run, you must cause it, when started running for such 134 | interactive use in the most ordinary way, to print or display an 135 | announcement including an appropriate copyright notice and a 136 | notice that there is no warranty (or else, saying that you provide 137 | a warranty) and that users may redistribute the program under 138 | these conditions, and telling the user how to view a copy of this 139 | License. (Exception: if the Program itself is interactive but 140 | does not normally print such an announcement, your work based on 141 | the Program is not required to print an announcement.) 142 | 143 | These requirements apply to the modified work as a whole. If 144 | identifiable sections of that work are not derived from the Program, 145 | and can be reasonably considered independent and separate works in 146 | themselves, then this License, and its terms, do not apply to those 147 | sections when you distribute them as separate works. But when you 148 | distribute the same sections as part of a whole which is a work based 149 | on the Program, the distribution of the whole must be on the terms of 150 | this License, whose permissions for other licensees extend to the 151 | entire whole, and thus to each and every part regardless of who wrote it. 152 | 153 | Thus, it is not the intent of this section to claim rights or contest 154 | your rights to work written entirely by you; rather, the intent is to 155 | exercise the right to control the distribution of derivative or 156 | collective works based on the Program. 157 | 158 | In addition, mere aggregation of another work not based on the Program 159 | with the Program (or with a work based on the Program) on a volume of 160 | a storage or distribution medium does not bring the other work under 161 | the scope of this License. 162 | 163 | 3. You may copy and distribute the Program (or a work based on it, 164 | under Section 2) in object code or executable form under the terms of 165 | Sections 1 and 2 above provided that you also do one of the following: 166 | 167 | a) Accompany it with the complete corresponding machine-readable 168 | source code, which must be distributed under the terms of Sections 169 | 1 and 2 above on a medium customarily used for software interchange; or, 170 | 171 | b) Accompany it with a written offer, valid for at least three 172 | years, to give any third party, for a charge no more than your 173 | cost of physically performing source distribution, a complete 174 | machine-readable copy of the corresponding source code, to be 175 | distributed under the terms of Sections 1 and 2 above on a medium 176 | customarily used for software interchange; or, 177 | 178 | c) Accompany it with the information you received as to the offer 179 | to distribute corresponding source code. (This alternative is 180 | allowed only for noncommercial distribution and only if you 181 | received the program in object code or executable form with such 182 | an offer, in accord with Subsection b above.) 183 | 184 | The source code for a work means the preferred form of the work for 185 | making modifications to it. For an executable work, complete source 186 | code means all the source code for all modules it contains, plus any 187 | associated interface definition files, plus the scripts used to 188 | control compilation and installation of the executable. However, as a 189 | special exception, the source code distributed need not include 190 | anything that is normally distributed (in either source or binary 191 | form) with the major components (compiler, kernel, and so on) of the 192 | operating system on which the executable runs, unless that component 193 | itself accompanies the executable. 194 | 195 | If distribution of executable or object code is made by offering 196 | access to copy from a designated place, then offering equivalent 197 | access to copy the source code from the same place counts as 198 | distribution of the source code, even though third parties are not 199 | compelled to copy the source along with the object code. 200 | 201 | 4. You may not copy, modify, sublicense, or distribute the Program 202 | except as expressly provided under this License. Any attempt 203 | otherwise to copy, modify, sublicense or distribute the Program is 204 | void, and will automatically terminate your rights under this License. 205 | However, parties who have received copies, or rights, from you under 206 | this License will not have their licenses terminated so long as such 207 | parties remain in full compliance. 208 | 209 | 5. You are not required to accept this License, since you have not 210 | signed it. However, nothing else grants you permission to modify or 211 | distribute the Program or its derivative works. These actions are 212 | prohibited by law if you do not accept this License. Therefore, by 213 | modifying or distributing the Program (or any work based on the 214 | Program), you indicate your acceptance of this License to do so, and 215 | all its terms and conditions for copying, distributing or modifying 216 | the Program or works based on it. 217 | 218 | 6. Each time you redistribute the Program (or any work based on the 219 | Program), the recipient automatically receives a license from the 220 | original licensor to copy, distribute or modify the Program subject to 221 | these terms and conditions. You may not impose any further 222 | restrictions on the recipients' exercise of the rights granted herein. 223 | You are not responsible for enforcing compliance by third parties to 224 | this License. 225 | 226 | 7. If, as a consequence of a court judgment or allegation of patent 227 | infringement or for any other reason (not limited to patent issues), 228 | conditions are imposed on you (whether by court order, agreement or 229 | otherwise) that contradict the conditions of this License, they do not 230 | excuse you from the conditions of this License. If you cannot 231 | distribute so as to satisfy simultaneously your obligations under this 232 | License and any other pertinent obligations, then as a consequence you 233 | may not distribute the Program at all. For example, if a patent 234 | license would not permit royalty-free redistribution of the Program by 235 | all those who receive copies directly or indirectly through you, then 236 | the only way you could satisfy both it and this License would be to 237 | refrain entirely from distribution of the Program. 238 | 239 | If any portion of this section is held invalid or unenforceable under 240 | any particular circumstance, the balance of the section is intended to 241 | apply and the section as a whole is intended to apply in other 242 | circumstances. 243 | 244 | It is not the purpose of this section to induce you to infringe any 245 | patents or other property right claims or to contest validity of any 246 | such claims; this section has the sole purpose of protecting the 247 | integrity of the free software distribution system, which is 248 | implemented by public license practices. Many people have made 249 | generous contributions to the wide range of software distributed 250 | through that system in reliance on consistent application of that 251 | system; it is up to the author/donor to decide if he or she is willing 252 | to distribute software through any other system and a licensee cannot 253 | impose that choice. 254 | 255 | This section is intended to make thoroughly clear what is believed to 256 | be a consequence of the rest of this License. 257 | 258 | 8. If the distribution and/or use of the Program is restricted in 259 | certain countries either by patents or by copyrighted interfaces, the 260 | original copyright holder who places the Program under this License 261 | may add an explicit geographical distribution limitation excluding 262 | those countries, so that distribution is permitted only in or among 263 | countries not thus excluded. In such case, this License incorporates 264 | the limitation as if written in the body of this License. 265 | 266 | 9. The Free Software Foundation may publish revised and/or new versions 267 | of the General Public License from time to time. Such new versions will 268 | be similar in spirit to the present version, but may differ in detail to 269 | address new problems or concerns. 270 | 271 | Each version is given a distinguishing version number. If the Program 272 | specifies a version number of this License which applies to it and "any 273 | later version", you have the option of following the terms and conditions 274 | either of that version or of any later version published by the Free 275 | Software Foundation. If the Program does not specify a version number of 276 | this License, you may choose any version ever published by the Free Software 277 | Foundation. 278 | 279 | 10. If you wish to incorporate parts of the Program into other free 280 | programs whose distribution conditions are different, write to the author 281 | to ask for permission. For software which is copyrighted by the Free 282 | Software Foundation, write to the Free Software Foundation; we sometimes 283 | make exceptions for this. Our decision will be guided by the two goals 284 | of preserving the free status of all derivatives of our free software and 285 | of promoting the sharing and reuse of software generally. 286 | 287 | NO WARRANTY 288 | 289 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 290 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 291 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 292 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 293 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 294 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 295 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 296 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 297 | REPAIR OR CORRECTION. 298 | 299 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 300 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 301 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 302 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 303 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 304 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 305 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 306 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 307 | POSSIBILITY OF SUCH DAMAGES. 308 | 309 | END OF TERMS AND CONDITIONS 310 | 311 | How to Apply These Terms to Your New Programs 312 | 313 | If you develop a new program, and you want it to be of the greatest 314 | possible use to the public, the best way to achieve this is to make it 315 | free software which everyone can redistribute and change under these terms. 316 | 317 | To do so, attach the following notices to the program. It is safest 318 | to attach them to the start of each source file to most effectively 319 | convey the exclusion of warranty; and each file should have at least 320 | the "copyright" line and a pointer to where the full notice is found. 321 | 322 | 323 | Copyright (C) 324 | 325 | This program is free software; you can redistribute it and/or modify 326 | it under the terms of the GNU General Public License as published by 327 | the Free Software Foundation; either version 2 of the License, or 328 | (at your option) any later version. 329 | 330 | This program is distributed in the hope that it will be useful, 331 | but WITHOUT ANY WARRANTY; without even the implied warranty of 332 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 333 | GNU General Public License for more details. 334 | 335 | You should have received a copy of the GNU General Public License along 336 | with this program; if not, write to the Free Software Foundation, Inc., 337 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 338 | 339 | Also add information on how to contact you by electronic and paper mail. 340 | 341 | If the program is interactive, make it output a short notice like this 342 | when it starts in an interactive mode: 343 | 344 | Gnomovision version 69, Copyright (C) year name of author 345 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 346 | This is free software, and you are welcome to redistribute it 347 | under certain conditions; type `show c' for details. 348 | 349 | The hypothetical commands `show w' and `show c' should show the appropriate 350 | parts of the General Public License. Of course, the commands you use may 351 | be called something other than `show w' and `show c'; they could even be 352 | mouse-clicks or menu items--whatever suits your program. 353 | 354 | You should also get your employer (if you work as a programmer) or your 355 | school, if any, to sign a "copyright disclaimer" for the program, if 356 | necessary. Here is a sample; alter the names: 357 | 358 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 359 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 360 | 361 | , 1 April 1989 362 | Ty Coon, President of Vice 363 | 364 | This General Public License does not permit incorporating your program into 365 | proprietary programs. If your program is a subroutine library, you may 366 | consider it more useful to permit linking proprietary applications with the 367 | library. If this is what you want to do, use the GNU Lesser General 368 | Public License instead of this License. 369 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | 3 | XDP Demo Apps 4 | ============= 5 | 6 | Testing XDP, on software and on hardware 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | 9 | This repository contains eBPF XDP demo applications. 10 | 11 | Most demos can be run on XDP compatible drivers or hardware. Each subdirectory 12 | provides instructions for loading the programs in “driver” and/or in “offload” 13 | mode. “Driver mode” loads the XDP program into the kernel where the processing 14 | is carried out by the host CPU, whilst “offloaded XDP” allows for the program 15 | to be run on hardware, such as with the Netronome Agilio® CX SmartNIC. 16 | 17 | To enable XDP offload on a Agilio CX, please refer to `Netronome eBPF user guides`_. 18 | 19 | .. _Netronome eBPF user guides: https://help.netronome.com/support/solutions/folders/36000172266 20 | 21 | List of available demos 22 | ~~~~~~~~~~~~~~~~~~~~~~~ 23 | 24 | The sources for each demo are located in a specific subdirectory. 25 | 26 | ======================== =============== 27 | Application Kernel Required 28 | ======================== =============== 29 | `Layer 4 Load Balancer`_ 4.17 30 | `Programmable RSS`_ 4.18 31 | `xdpdump`_ 4.18 32 | ======================== =============== 33 | 34 | .. _Layer 4 Load Balancer: l4lb/ 35 | .. _Programmable RSS: programmable_rss/ 36 | .. _xdpdump: xdpdump/ 37 | 38 | libbpf 39 | ~~~~~~ 40 | 41 | The ``libbpf`` directory is a git submodule and contains libraries required for 42 | compiling the samples. To obtain the submodule content, the following git 43 | clone command is required: 44 | 45 | git clone --recurse-submodules https://github.com/Netronome/bpf-samples.git 46 | 47 | Notes 48 | ~~~~~ 49 | 50 | - These applications are prototypes and are not suitable for production use. 51 | -------------------------------------------------------------------------------- /headers/bpf_endian.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* Copied from $(LINUX)/tools/testing/selftests/bpf/bpf_endian.h */ 3 | #ifndef __BPF_ENDIAN__ 4 | #define __BPF_ENDIAN__ 5 | 6 | #include 7 | 8 | /* LLVM's BPF target selects the endianness of the CPU 9 | * it compiles on, or the user specifies (bpfel/bpfeb), 10 | * respectively. The used __BYTE_ORDER__ is defined by 11 | * the compiler, we cannot rely on __BYTE_ORDER from 12 | * libc headers, since it doesn't reflect the actual 13 | * requested byte order. 14 | * 15 | * Note, LLVM's BPF target has different __builtin_bswapX() 16 | * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE 17 | * in bpfel and bpfeb case, which means below, that we map 18 | * to cpu_to_be16(). We could use it unconditionally in BPF 19 | * case, but better not rely on it, so that this header here 20 | * can be used from application and BPF program side, which 21 | * use different targets. 22 | */ 23 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 24 | # define __bpf_ntohs(x)__builtin_bswap16(x) 25 | # define __bpf_htons(x)__builtin_bswap16(x) 26 | # define __bpf_constant_ntohs(x)___constant_swab16(x) 27 | # define __bpf_constant_htons(x)___constant_swab16(x) 28 | # define __bpf_ntohl(x)__builtin_bswap32(x) 29 | # define __bpf_htonl(x)__builtin_bswap32(x) 30 | # define __bpf_constant_ntohl(x)___constant_swab32(x) 31 | # define __bpf_constant_htonl(x)___constant_swab32(x) 32 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 33 | # define __bpf_ntohs(x)(x) 34 | # define __bpf_htons(x)(x) 35 | # define __bpf_constant_ntohs(x)(x) 36 | # define __bpf_constant_htons(x)(x) 37 | # define __bpf_ntohl(x)(x) 38 | # define __bpf_htonl(x)(x) 39 | # define __bpf_constant_ntohl(x)(x) 40 | # define __bpf_constant_htonl(x)(x) 41 | #else 42 | # error "Fix your compiler's __BYTE_ORDER__?!" 43 | #endif 44 | 45 | #define bpf_htons(x)\ 46 | (__builtin_constant_p(x) ?\ 47 | __bpf_constant_htons(x) : __bpf_htons(x)) 48 | #define bpf_ntohs(x)\ 49 | (__builtin_constant_p(x) ?\ 50 | __bpf_constant_ntohs(x) : __bpf_ntohs(x)) 51 | #define bpf_htonl(x)\ 52 | (__builtin_constant_p(x) ?\ 53 | __bpf_constant_htonl(x) : __bpf_htonl(x)) 54 | #define bpf_ntohl(x)\ 55 | (__builtin_constant_p(x) ?\ 56 | __bpf_constant_ntohl(x) : __bpf_ntohl(x)) 57 | 58 | #endif /* __BPF_ENDIAN__ */ 59 | -------------------------------------------------------------------------------- /headers/bpf_helpers.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* Copied from $(LINUX)/tools/testing/selftests/bpf/bpf_helpers.h */ 3 | #ifndef __BPF_HELPERS_H 4 | #define __BPF_HELPERS_H 5 | 6 | /* helper macro to place programs, maps, license in 7 | * different sections in elf_bpf file. Section names 8 | * are interpreted by elf_bpf loader 9 | */ 10 | #define SEC(NAME) __attribute__((section(NAME), used)) 11 | 12 | /* helper functions called from eBPF programs written in C */ 13 | static void *(*bpf_map_lookup_elem)(void *map, void *key) = 14 | (void *) BPF_FUNC_map_lookup_elem; 15 | static int (*bpf_map_update_elem)(void *map, void *key, void *value, 16 | unsigned long long flags) = 17 | (void *) BPF_FUNC_map_update_elem; 18 | static int (*bpf_map_delete_elem)(void *map, void *key) = 19 | (void *) BPF_FUNC_map_delete_elem; 20 | static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) = 21 | (void *) BPF_FUNC_probe_read; 22 | static unsigned long long (*bpf_ktime_get_ns)(void) = 23 | (void *) BPF_FUNC_ktime_get_ns; 24 | static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = 25 | (void *) BPF_FUNC_trace_printk; 26 | static void (*bpf_tail_call)(void *ctx, void *map, int index) = 27 | (void *) BPF_FUNC_tail_call; 28 | static unsigned long long (*bpf_get_smp_processor_id)(void) = 29 | (void *) BPF_FUNC_get_smp_processor_id; 30 | static unsigned long long (*bpf_get_current_pid_tgid)(void) = 31 | (void *) BPF_FUNC_get_current_pid_tgid; 32 | static unsigned long long (*bpf_get_current_uid_gid)(void) = 33 | (void *) BPF_FUNC_get_current_uid_gid; 34 | static int (*bpf_get_current_comm)(void *buf, int buf_size) = 35 | (void *) BPF_FUNC_get_current_comm; 36 | static unsigned long long (*bpf_perf_event_read)(void *map, 37 | unsigned long long flags) = 38 | (void *) BPF_FUNC_perf_event_read; 39 | static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = 40 | (void *) BPF_FUNC_clone_redirect; 41 | static int (*bpf_redirect)(int ifindex, int flags) = 42 | (void *) BPF_FUNC_redirect; 43 | static int (*bpf_perf_event_output)(void *ctx, void *map, 44 | unsigned long long flags, void *data, 45 | int size) = 46 | (void *) BPF_FUNC_perf_event_output; 47 | static int (*bpf_get_stackid)(void *ctx, void *map, int flags) = 48 | (void *) BPF_FUNC_get_stackid; 49 | static int (*bpf_probe_write_user)(void *dst, void *src, int size) = 50 | (void *) BPF_FUNC_probe_write_user; 51 | static int (*bpf_current_task_under_cgroup)(void *map, int index) = 52 | (void *) BPF_FUNC_current_task_under_cgroup; 53 | static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = 54 | (void *) BPF_FUNC_skb_get_tunnel_key; 55 | static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = 56 | (void *) BPF_FUNC_skb_set_tunnel_key; 57 | static int (*bpf_skb_get_tunnel_opt)(void *ctx, void *md, int size) = 58 | (void *) BPF_FUNC_skb_get_tunnel_opt; 59 | static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) = 60 | (void *) BPF_FUNC_skb_set_tunnel_opt; 61 | static unsigned long long (*bpf_get_prandom_u32)(void) = 62 | (void *) BPF_FUNC_get_prandom_u32; 63 | static int (*bpf_xdp_adjust_head)(void *ctx, int offset) = 64 | (void *) BPF_FUNC_xdp_adjust_head; 65 | 66 | /* llvm builtin functions that eBPF C program may use to 67 | * emit BPF_LD_ABS and BPF_LD_IND instructions 68 | */ 69 | struct sk_buff; 70 | unsigned long long load_byte(void *skb, 71 | unsigned long long off) asm("llvm.bpf.load.byte"); 72 | unsigned long long load_half(void *skb, 73 | unsigned long long off) asm("llvm.bpf.load.half"); 74 | unsigned long long load_word(void *skb, 75 | unsigned long long off) asm("llvm.bpf.load.word"); 76 | 77 | /* a helper structure used by eBPF C program 78 | * to describe map attributes to elf_bpf loader 79 | */ 80 | struct bpf_map_def { 81 | unsigned int type; 82 | unsigned int key_size; 83 | unsigned int value_size; 84 | unsigned int max_entries; 85 | unsigned int map_flags; 86 | unsigned int inner_map_idx; 87 | }; 88 | 89 | static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = 90 | (void *) BPF_FUNC_skb_load_bytes; 91 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 92 | (void *) BPF_FUNC_skb_store_bytes; 93 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 94 | (void *) BPF_FUNC_l3_csum_replace; 95 | static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = 96 | (void *) BPF_FUNC_l4_csum_replace; 97 | static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) = 98 | (void *) BPF_FUNC_skb_under_cgroup; 99 | static int (*bpf_skb_change_head)(void *, int len, int flags) = 100 | (void *) BPF_FUNC_skb_change_head; 101 | 102 | #if defined(__x86_64__) 103 | 104 | #define PT_REGS_PARM1(x) ((x)->di) 105 | #define PT_REGS_PARM2(x) ((x)->si) 106 | #define PT_REGS_PARM3(x) ((x)->dx) 107 | #define PT_REGS_PARM4(x) ((x)->cx) 108 | #define PT_REGS_PARM5(x) ((x)->r8) 109 | #define PT_REGS_RET(x) ((x)->sp) 110 | #define PT_REGS_FP(x) ((x)->bp) 111 | #define PT_REGS_RC(x) ((x)->ax) 112 | #define PT_REGS_SP(x) ((x)->sp) 113 | #define PT_REGS_IP(x) ((x)->ip) 114 | 115 | #elif defined(__s390x__) 116 | 117 | #define PT_REGS_PARM1(x) ((x)->gprs[2]) 118 | #define PT_REGS_PARM2(x) ((x)->gprs[3]) 119 | #define PT_REGS_PARM3(x) ((x)->gprs[4]) 120 | #define PT_REGS_PARM4(x) ((x)->gprs[5]) 121 | #define PT_REGS_PARM5(x) ((x)->gprs[6]) 122 | #define PT_REGS_RET(x) ((x)->gprs[14]) 123 | #define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ 124 | #define PT_REGS_RC(x) ((x)->gprs[2]) 125 | #define PT_REGS_SP(x) ((x)->gprs[15]) 126 | #define PT_REGS_IP(x) ((x)->psw.addr) 127 | 128 | #elif defined(__aarch64__) 129 | 130 | #define PT_REGS_PARM1(x) ((x)->regs[0]) 131 | #define PT_REGS_PARM2(x) ((x)->regs[1]) 132 | #define PT_REGS_PARM3(x) ((x)->regs[2]) 133 | #define PT_REGS_PARM4(x) ((x)->regs[3]) 134 | #define PT_REGS_PARM5(x) ((x)->regs[4]) 135 | #define PT_REGS_RET(x) ((x)->regs[30]) 136 | #define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */ 137 | #define PT_REGS_RC(x) ((x)->regs[0]) 138 | #define PT_REGS_SP(x) ((x)->sp) 139 | #define PT_REGS_IP(x) ((x)->pc) 140 | 141 | #elif defined(__powerpc__) 142 | 143 | #define PT_REGS_PARM1(x) ((x)->gpr[3]) 144 | #define PT_REGS_PARM2(x) ((x)->gpr[4]) 145 | #define PT_REGS_PARM3(x) ((x)->gpr[5]) 146 | #define PT_REGS_PARM4(x) ((x)->gpr[6]) 147 | #define PT_REGS_PARM5(x) ((x)->gpr[7]) 148 | #define PT_REGS_RC(x) ((x)->gpr[3]) 149 | #define PT_REGS_SP(x) ((x)->sp) 150 | #define PT_REGS_IP(x) ((x)->nip) 151 | 152 | #elif defined(__sparc__) 153 | 154 | #define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) 155 | #define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) 156 | #define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2]) 157 | #define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3]) 158 | #define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4]) 159 | #define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) 160 | #define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) 161 | #define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) 162 | #if defined(__arch64__) 163 | #define PT_REGS_IP(x) ((x)->tpc) 164 | #else 165 | #define PT_REGS_IP(x) ((x)->pc) 166 | #endif 167 | 168 | #endif 169 | 170 | #ifdef __powerpc__ 171 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) 172 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 173 | #elif defined(__sparc__) 174 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) 175 | #define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP 176 | #else 177 | #define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ \ 178 | bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) 179 | #define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ \ 180 | bpf_probe_read(&(ip), sizeof(ip), \ 181 | (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) 182 | #endif 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /headers/jhash.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_JHASH_H 2 | #define _LINUX_JHASH_H 3 | 4 | /* Copied from $(LINUX)/include/linux/jhash.h (kernel 4.18) */ 5 | 6 | /* jhash.h: Jenkins hash support. 7 | * 8 | * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net) 9 | * 10 | * http://burtleburtle.net/bob/hash/ 11 | * 12 | * These are the credits from Bob's sources: 13 | * 14 | * lookup3.c, by Bob Jenkins, May 2006, Public Domain. 15 | * 16 | * These are functions for producing 32-bit hashes for hash table lookup. 17 | * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() 18 | * are externally useful functions. Routines to test the hash are included 19 | * if SELF_TEST is defined. You can use this free for any purpose. It's in 20 | * the public domain. It has no warranty. 21 | * 22 | * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) 23 | */ 24 | 25 | static inline __u32 rol32(__u32 word, unsigned int shift) 26 | { 27 | return (word << shift) | (word >> ((-shift) & 31)); 28 | } 29 | 30 | /* copy paste of jhash from kernel sources (include/linux/jhash.h) to make sure 31 | * LLVM can compile it into valid sequence of BPF instructions 32 | */ 33 | #define __jhash_mix(a, b, c) \ 34 | { \ 35 | a -= c; a ^= rol32(c, 4); c += b; \ 36 | b -= a; b ^= rol32(a, 6); a += c; \ 37 | c -= b; c ^= rol32(b, 8); b += a; \ 38 | a -= c; a ^= rol32(c, 16); c += b; \ 39 | b -= a; b ^= rol32(a, 19); a += c; \ 40 | c -= b; c ^= rol32(b, 4); b += a; \ 41 | } 42 | 43 | #define __jhash_final(a, b, c) \ 44 | { \ 45 | c ^= b; c -= rol32(b, 14); \ 46 | a ^= c; a -= rol32(c, 11); \ 47 | b ^= a; b -= rol32(a, 25); \ 48 | c ^= b; c -= rol32(b, 16); \ 49 | a ^= c; a -= rol32(c, 4); \ 50 | b ^= a; b -= rol32(a, 14); \ 51 | c ^= b; c -= rol32(b, 24); \ 52 | } 53 | 54 | #define JHASH_INITVAL 0xdeadbeef 55 | 56 | typedef unsigned int u32; 57 | 58 | /* jhash - hash an arbitrary key 59 | * @k: sequence of bytes as key 60 | * @length: the length of the key 61 | * @initval: the previous hash, or an arbitray value 62 | * 63 | * The generic version, hashes an arbitrary sequence of bytes. 64 | * No alignment or length assumptions are made about the input key. 65 | * 66 | * Returns the hash value of the key. The result depends on endianness. 67 | */ 68 | static inline u32 jhash(const void *key, u32 length, u32 initval) 69 | { 70 | u32 a, b, c; 71 | const unsigned char *k = key; 72 | 73 | /* Set up the internal state */ 74 | a = b = c = JHASH_INITVAL + length + initval; 75 | 76 | /* All but the last block: affect some 32 bits of (a,b,c) */ 77 | while (length > 12) { 78 | a += *(u32 *)(k); 79 | b += *(u32 *)(k + 4); 80 | c += *(u32 *)(k + 8); 81 | __jhash_mix(a, b, c); 82 | length -= 12; 83 | k += 12; 84 | } 85 | /* Last block: affect all 32 bits of (c) */ 86 | switch (length) { 87 | case 12: c += (u32)k[11]<<24; /* fall through */ 88 | case 11: c += (u32)k[10]<<16; /* fall through */ 89 | case 10: c += (u32)k[9]<<8; /* fall through */ 90 | case 9: c += k[8]; /* fall through */ 91 | case 8: b += (u32)k[7]<<24; /* fall through */ 92 | case 7: b += (u32)k[6]<<16; /* fall through */ 93 | case 6: b += (u32)k[5]<<8; /* fall through */ 94 | case 5: b += k[4]; /* fall through */ 95 | case 4: a += (u32)k[3]<<24; /* fall through */ 96 | case 3: a += (u32)k[2]<<16; /* fall through */ 97 | case 2: a += (u32)k[1]<<8; /* fall through */ 98 | case 1: a += k[0]; 99 | __jhash_final(a, b, c); 100 | case 0: /* Nothing left to add */ 101 | break; 102 | } 103 | 104 | return c; 105 | } 106 | 107 | /* jhash2 - hash an array of u32's 108 | * @k: the key which must be an array of u32's 109 | * @length: the number of u32's in the key 110 | * @initval: the previous hash, or an arbitray value 111 | * 112 | * Returns the hash value of the key. 113 | */ 114 | static inline u32 jhash2(const u32 *k, u32 length, u32 initval) 115 | { 116 | u32 a, b, c; 117 | 118 | /* Set up the internal state */ 119 | a = b = c = JHASH_INITVAL + (length<<2) + initval; 120 | 121 | /* Handle most of the key */ 122 | while (length > 3) { 123 | a += k[0]; 124 | b += k[1]; 125 | c += k[2]; 126 | __jhash_mix(a, b, c); 127 | length -= 3; 128 | k += 3; 129 | } 130 | 131 | /* Handle the last 3 u32's */ 132 | switch (length) { 133 | case 3: c += k[2]; /* fall through */ 134 | case 2: b += k[1]; /* fall through */ 135 | case 1: a += k[0]; 136 | __jhash_final(a, b, c); 137 | case 0: /* Nothing left to add */ 138 | break; 139 | } 140 | 141 | return c; 142 | } 143 | 144 | 145 | /* __jhash_nwords - hash exactly 3, 2 or 1 word(s) */ 146 | static inline u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) 147 | { 148 | a += initval; 149 | b += initval; 150 | c += initval; 151 | 152 | __jhash_final(a, b, c); 153 | 154 | return c; 155 | } 156 | 157 | static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) 158 | { 159 | return __jhash_nwords(a, b, c, initval + JHASH_INITVAL + (3 << 2)); 160 | } 161 | 162 | static inline u32 jhash_2words(u32 a, u32 b, u32 initval) 163 | { 164 | return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); 165 | } 166 | 167 | static inline u32 jhash_1word(u32 a, u32 initval) 168 | { 169 | return __jhash_nwords(a, 0, 0, initval + JHASH_INITVAL + (1 << 2)); 170 | } 171 | 172 | #endif /* _LINUX_JHASH_H */ 173 | -------------------------------------------------------------------------------- /headers/perf-sys.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* Copied from $(LINUX)/tools/perf/perf-sys.h (kernel 4.18) */ 3 | #ifndef _PERF_SYS_H 4 | #define _PERF_SYS_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | /* 12 | * remove the following headers to allow for userspace program compilation 13 | * #include 14 | * #include 15 | */ 16 | #ifdef __powerpc__ 17 | #define CPUINFO_PROC {"cpu"} 18 | #endif 19 | 20 | #ifdef __s390__ 21 | #define CPUINFO_PROC {"vendor_id"} 22 | #endif 23 | 24 | #ifdef __sh__ 25 | #define CPUINFO_PROC {"cpu type"} 26 | #endif 27 | 28 | #ifdef __hppa__ 29 | #define CPUINFO_PROC {"cpu"} 30 | #endif 31 | 32 | #ifdef __sparc__ 33 | #define CPUINFO_PROC {"cpu"} 34 | #endif 35 | 36 | #ifdef __alpha__ 37 | #define CPUINFO_PROC {"cpu model"} 38 | #endif 39 | 40 | #ifdef __arm__ 41 | #define CPUINFO_PROC {"model name", "Processor"} 42 | #endif 43 | 44 | #ifdef __mips__ 45 | #define CPUINFO_PROC {"cpu model"} 46 | #endif 47 | 48 | #ifdef __arc__ 49 | #define CPUINFO_PROC {"Processor"} 50 | #endif 51 | 52 | #ifdef __xtensa__ 53 | #define CPUINFO_PROC {"core ID"} 54 | #endif 55 | 56 | #ifndef CPUINFO_PROC 57 | #define CPUINFO_PROC { "model name", } 58 | #endif 59 | 60 | static inline int 61 | sys_perf_event_open(struct perf_event_attr *attr, 62 | pid_t pid, int cpu, int group_fd, 63 | unsigned long flags) 64 | { 65 | int fd; 66 | 67 | fd = syscall(__NR_perf_event_open, attr, pid, cpu, 68 | group_fd, flags); 69 | 70 | #ifdef HAVE_ATTR_TEST 71 | if (unlikely(test_attr__enabled)) 72 | test_attr__open(attr, pid, cpu, fd, group_fd, flags); 73 | #endif 74 | return fd; 75 | } 76 | 77 | #endif /* _PERF_SYS_H */ 78 | -------------------------------------------------------------------------------- /l4lb/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | 3 | LLVM_VERSION ?= 4 | LLVM := $(shell clang$(LLVM_VERSION) --version) 5 | CLANG_FLAGS ?= -W -Wall \ 6 | -Wno-compare-distinct-pointer-types 7 | 8 | SRCS=$(wildcard *.c) 9 | OBJS=$(patsubst %.c,%.o,$(SRCS)) 10 | Q ?= @ 11 | 12 | INCLUDE_DIRS ?= -I../headers/ 13 | 14 | %.o: %.c 15 | @echo "\tLLVM CC $@" 16 | $(Q) clang$(LLVM_VERSION) $(INCLUDE_DIRS) -O2 -emit-llvm -c $< $(CLANG_FLAGS) -o $(patsubst %.o,%.llvm,$@) 17 | $(Q) llc$(LLVM_VERSION) -march=bpf -filetype=obj -o $@ $(patsubst %.o,%.llvm,$@) 18 | $(Q) rm $(patsubst %.o,%.llvm,$@) 19 | 20 | ifeq ($(LLVM),) 21 | all: 22 | $(warning Install LLVM to compile BPF sources) 23 | else 24 | all: $(OBJS) 25 | endif 26 | 27 | clean: 28 | rm -f *.llvm 29 | rm -f *.o 30 | 31 | .PHONY: all clean 32 | -------------------------------------------------------------------------------- /l4lb/README.rst: -------------------------------------------------------------------------------- 1 | Layer 4 Load Balancer Demo 2 | ========================== 3 | 4 | This program will demonstrate how a XDP load balancer can be used to distribute 5 | incoming traffic by hashing the layer 3 and layer 4 headers. 6 | 7 | The XDP program, will process incoming network packets and compute a hash 8 | based on the sender IP address, along with the TCP or UDP network ports. 9 | This hash value is subsequently used as the key for a eBPF map. 10 | 11 | The eBPF map is filled with the available servers to which the XDP program can 12 | redirect the packet to. The XDP program will extend and insert an outer IP 13 | header with this map data. After processing, the program will subsequently 14 | send the packet back out of the network interface to the destination server. 15 | 16 | The map fill and stats scripts are written in python and utilize bpftool to 17 | showcase how a program can be deployed using iproute2 and bpftool utilities. 18 | 19 | Minimum Requirements for Demo 20 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 21 | 22 | - Linux kernel 4.17 23 | - iproute2 v4.16.0 (a.k.a ss180402) 24 | - clang / LLVM 4.0 25 | - bpftool 26 | - Python 3 27 | - Agilio® eBPF firmware (only for HW offload) - July 2018 28 | (available from `Netronome's support website`_) 29 | 30 | .. _Netronome's support website: https://help.netronome.com/ 31 | 32 | Loading the Demo 33 | ~~~~~~~~~~~~~~~~ 34 | 35 | To compile the XDP program :: 36 | 37 | $ make 38 | 39 | The program can be loaded using iproute2 using the following commands 40 | 41 | XDP driver mode :: 42 | 43 | # ip link set dev { DEV } xdpdrv obj l4lb_xdp.o sec xdp 44 | 45 | XDP offload :: 46 | 47 | # ip link set dev { DEV } xdpoffload obj l4lb_xdp.o sec xdp 48 | 49 | The load balancer map can be filled with the l4lb_map.py script. Note that 50 | sample files with lists of destinations are provided under 51 | `destination_samples/`_ :: 52 | 53 | # ./l4lb_map.py -i { DEV } -f { file containing destinations } 54 | 55 | Traffic statistics may be seen using the l4lb_stats.py script :: 56 | 57 | # ./l4lb_stats.py -i { DEV } 58 | 59 | .. _destination_samples/: destination_samples/ 60 | 61 | Traffic Generation 62 | ~~~~~~~~~~~~~~~~~~ 63 | 64 | Traffic can be generated using a variety of tools. A command is shown below 65 | which utilises the hping3 utility to generate the traffic. The command should 66 | be run on a different host connected to the server running the eBPF l4lb 67 | program. In this example the traffic generator uses interface ens0 and is 68 | transmitting traffic to IP address 10.0.0.4 :: 69 | 70 | hping3 10.0.0.4 --rand-source -i ens0 --flood 71 | 72 | Example 73 | ~~~~~~~ 74 | 75 | To demo the program on offload mode on interface ens4np0, with 32 destinations :: 76 | 77 | # ip link set dev ens4np0 xdpoffload obj l4lb_xdp.o sec xdp 78 | Note: 12 bytes struct bpf_elf_map fixup performed due to size mismatch! 79 | 80 | # ./l4lb_map.py -i ens4np0 -f destination_samples/32_destinations.csv 81 | Loading file with 32 destinations 82 | 83 | # ./l4lb_stats.py -i ens4np0 84 | == Load balancer outbound statistics [Offload] == 85 | 86 | 1 10.0.0.57 1,029,744 pkts/s 1,186,266,224 bits/s 87 | 2 10.0.125.19 1,031,841 pkts/s 1,188,681,760 bits/s 88 | 3 10.0.129.60 1,033,649 pkts/s 1,190,763,984 bits/s 89 | 4 10.0.14.88 1,031,274 pkts/s 1,188,028,704 bits/s 90 | 5 10.0.143.99 1,032,110 pkts/s 1,188,991,816 bits/s 91 | 6 10.0.159.176 1,031,466 pkts/s 1,188,249,616 bits/s 92 | 7 10.0.16.109 1,031,213 pkts/s 1,187,957,968 bits/s 93 | 8 10.0.161.129 1,031,025 pkts/s 1,187,740,928 bits/s 94 | 9 10.0.175.130 1,032,664 pkts/s 1,189,629,368 bits/s 95 | 10 10.0.178.75 1,032,625 pkts/s 1,189,584,800 bits/s 96 | 11 10.0.181.34 1,031,332 pkts/s 1,188,094,584 bits/s 97 | 12 10.0.185.52 1,033,361 pkts/s 1,190,432,608 bits/s 98 | 13 10.0.192.32 1,032,855 pkts/s 1,189,849,312 bits/s 99 | 14 10.0.199.54 1,032,126 pkts/s 1,189,009,256 bits/s 100 | 15 10.0.214.65 1,032,921 pkts/s 1,189,925,864 bits/s 101 | 16 10.0.23.41 1,033,084 pkts/s 1,190,112,864 bits/s 102 | 17 10.0.234.48 1,031,888 pkts/s 1,188,735,048 bits/s 103 | 18 10.0.24.77 1,031,594 pkts/s 1,188,396,896 bits/s 104 | 19 10.0.244.158 1,031,127 pkts/s 1,187,859,136 bits/s 105 | 20 10.0.31.144 1,032,068 pkts/s 1,188,942,400 bits/s 106 | 21 10.0.32.134 1,031,787 pkts/s 1,188,619,744 bits/s 107 | 22 10.0.32.35 1,031,222 pkts/s 1,187,968,624 bits/s 108 | 23 10.0.50.179 1,031,597 pkts/s 1,188,400,768 bits/s 109 | 24 10.0.56.49 1,032,840 pkts/s 1,189,831,872 bits/s 110 | 25 10.0.63.10 1,031,564 pkts/s 1,188,362,008 bits/s 111 | 26 10.0.75.126 1,032,512 pkts/s 1,189,454,960 bits/s 112 | 27 10.0.75.197 1,030,993 pkts/s 1,187,705,080 bits/s 113 | 28 10.0.75.209 1,033,445 pkts/s 1,190,529,504 bits/s 114 | 29 10.0.89.127 1,033,593 pkts/s 1,190,700,032 bits/s 115 | 30 10.0.90.135 1,031,819 pkts/s 1,188,655,600 bits/s 116 | 31 10.0.90.214 1,032,841 pkts/s 1,189,832,848 bits/s 117 | 32 10.0.92.11 1,032,581 pkts/s 1,189,534,416 bits/s 118 | 119 | [Totals] 33,026,761 pkts/s 38,046,848,592 bits/s 120 | 121 | Note: This example was produced with a high performance traffic generator, 122 | lower rates are expected with hping3. 123 | 124 | Removing the Demo 125 | ~~~~~~~~~~~~~~~~ 126 | 127 | XDP driver mode :: 128 | 129 | # ip link set dev { DEV } xdpdrv off 130 | 131 | XDP offload :: 132 | 133 | # ip link set dev { DEV } xdpoffload off 134 | -------------------------------------------------------------------------------- /l4lb/bpftool_utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 3 | # Copyright (c) 2018 Netronome Systems, Inc. 4 | 5 | import json 6 | import subprocess 7 | import struct 8 | import sys 9 | 10 | def check_output_json(cmd): 11 | return json.loads(subprocess.check_output(cmd, shell=True).decode("utf-8")) 12 | 13 | def get_xdp_prog(interface): 14 | cmd_iplink = 'ip -j link show %s' % interface 15 | iplink = check_output_json(cmd_iplink) 16 | return iplink[0]['xdp']['prog']['id'] 17 | 18 | def get_map_ids(interface): 19 | prog_id = get_xdp_prog(interface) 20 | cmd_progshow = 'bpftool prog show id %d -p' % prog_id 21 | prog_info = check_output_json(cmd_progshow) 22 | 23 | maps = check_output_json('bpftool map -p') 24 | map_ids = [] 25 | 26 | for m in maps: 27 | if m['id'] in prog_info['map_ids']: 28 | map_ids.append(m['id']) 29 | return map_ids 30 | 31 | def get_map_entries(map_id): 32 | cmd_mapshow = 'bpftool map show id %s -p' % map_id 33 | map_info = check_output_json(cmd_mapshow) 34 | return map_info['max_entries'] 35 | 36 | def get_map_dev(map_id): 37 | cmd_mapshow = 'bpftool map show id %s -p' % map_id 38 | map_info = check_output_json(cmd_mapshow) 39 | 40 | if "dev" in map_info: 41 | return "Offload" 42 | else: 43 | return "Driver" 44 | 45 | def dump_map(map_id): 46 | cmd_map = 'bpftool map dump id %s -p' % map_id 47 | return check_output_json(cmd_map) 48 | 49 | def hex_list_to_int(hex_list): 50 | hex_str = ''.join([byte.replace('0x', '') for byte in hex_list]) 51 | return (int.from_bytes(bytes.fromhex(hex_str), byteorder='little')) 52 | -------------------------------------------------------------------------------- /l4lb/destination_samples/128_destinations.csv: -------------------------------------------------------------------------------- 1 | 10.0.88.205, 00:15:4d:58:cd:73 2 | 10.0.18.70, 00:15:4d:12:46:fd 3 | 10.0.195.112, 00:15:4d:c3:70:25 4 | 10.0.78.90, 00:15:4d:4e:5a:71 5 | 10.0.163.40, 00:15:4d:a3:28:8f 6 | 10.0.73.36, 00:15:4d:49:24:22 7 | 10.0.84.187, 00:15:4d:54:bb:24 8 | 10.0.91.5, 00:15:4d:5b:05:c4 9 | 10.0.94.163, 00:15:4d:5e:a3:8f 10 | 10.0.107.139, 00:15:4d:6b:8b:b3 11 | 10.0.62.8, 00:15:4d:3e:08:5b 12 | 10.0.167.5, 00:15:4d:a7:05:6a 13 | 10.0.95.82, 00:15:4d:5f:52:15 14 | 10.0.103.166, 00:15:4d:67:a6:1b 15 | 10.0.130.78, 00:15:4d:82:4e:d3 16 | 10.0.160.22, 00:15:4d:a0:16:15 17 | 10.0.26.39, 00:15:4d:1a:27:ba 18 | 10.0.28.178, 00:15:4d:1c:b2:a7 19 | 10.0.61.219, 00:15:4d:3d:db:e1 20 | 10.0.136.80, 00:15:4d:88:50:7b 21 | 10.0.143.131, 00:15:4d:8f:83:43 22 | 10.0.59.23, 00:15:4d:3b:17:ce 23 | 10.0.33.220, 00:15:4d:21:dc:45 24 | 10.0.115.238, 00:15:4d:73:ee:78 25 | 10.0.94.5, 00:15:4d:5e:05:7d 26 | 10.0.169.254, 00:15:4d:a9:fe:fa 27 | 10.0.67.201, 00:15:4d:43:c9:a2 28 | 10.0.179.40, 00:15:4d:b3:28:64 29 | 10.0.178.157, 00:15:4d:b2:9d:bd 30 | 10.0.234.135, 00:15:4d:ea:87:f6 31 | 10.0.215.81, 00:15:4d:d7:51:a3 32 | 10.0.204.92, 00:15:4d:cc:5c:6a 33 | 10.0.2.126, 00:15:4d:02:7e:0c 34 | 10.0.233.124, 00:15:4d:e9:7c:fe 35 | 10.0.249.99, 00:15:4d:f9:63:14 36 | 10.0.74.62, 00:15:4d:4a:3e:e6 37 | 10.0.240.222, 00:15:4d:f0:de:c9 38 | 10.0.215.184, 00:15:4d:d7:b8:59 39 | 10.0.126.211, 00:15:4d:7e:d3:f9 40 | 10.0.75.224, 00:15:4d:4b:e0:83 41 | 10.0.63.180, 00:15:4d:3f:b4:33 42 | 10.0.146.203, 00:15:4d:92:cb:70 43 | 10.0.49.18, 00:15:4d:31:12:b6 44 | 10.0.103.246, 00:15:4d:67:f6:73 45 | 10.0.213.88, 00:15:4d:d5:58:5f 46 | 10.0.237.180, 00:15:4d:ed:b4:c0 47 | 10.0.5.222, 00:15:4d:05:de:6e 48 | 10.0.200.90, 00:15:4d:c8:5a:c3 49 | 10.0.98.151, 00:15:4d:62:97:bd 50 | 10.0.24.54, 00:15:4d:18:36:45 51 | 10.0.26.187, 00:15:4d:1a:bb:a2 52 | 10.0.125.254, 00:15:4d:7d:fe:92 53 | 10.0.197.161, 00:15:4d:c5:a1:b9 54 | 10.0.140.219, 00:15:4d:8c:db:aa 55 | 10.0.150.216, 00:15:4d:96:d8:f2 56 | 10.0.244.207, 00:15:4d:f4:cf:c6 57 | 10.0.111.29, 00:15:4d:6f:1d:0c 58 | 10.0.118.29, 00:15:4d:76:1d:e1 59 | 10.0.166.72, 00:15:4d:a6:48:9e 60 | 10.0.186.225, 00:15:4d:ba:e1:46 61 | 10.0.165.164, 00:15:4d:a5:a4:59 62 | 10.0.155.148, 00:15:4d:9b:94:ab 63 | 10.0.27.97, 00:15:4d:1b:61:8e 64 | 10.0.94.250, 00:15:4d:5e:fa:53 65 | 10.0.251.119, 00:15:4d:fb:77:83 66 | 10.0.53.117, 00:15:4d:35:75:1b 67 | 10.0.50.29, 00:15:4d:32:1d:df 68 | 10.0.221.217, 00:15:4d:dd:d9:48 69 | 10.0.43.49, 00:15:4d:2b:31:ea 70 | 10.0.46.83, 00:15:4d:2e:53:44 71 | 10.0.84.51, 00:15:4d:54:33:c9 72 | 10.0.79.91, 00:15:4d:4f:5b:03 73 | 10.0.50.159, 00:15:4d:32:9f:76 74 | 10.0.108.221, 00:15:4d:6c:dd:54 75 | 10.0.113.222, 00:15:4d:71:de:39 76 | 10.0.9.3, 00:15:4d:09:03:6b 77 | 10.0.39.182, 00:15:4d:27:b6:f1 78 | 10.0.240.28, 00:15:4d:f0:1c:56 79 | 10.0.234.128, 00:15:4d:ea:80:e7 80 | 10.0.188.84, 00:15:4d:bc:54:34 81 | 10.0.107.88, 00:15:4d:6b:58:28 82 | 10.0.124.246, 00:15:4d:7c:f6:20 83 | 10.0.12.20, 00:15:4d:0c:14:4e 84 | 10.0.224.183, 00:15:4d:e0:b7:e4 85 | 10.0.34.66, 00:15:4d:22:42:97 86 | 10.0.67.128, 00:15:4d:43:80:1e 87 | 10.0.63.198, 00:15:4d:3f:c6:84 88 | 10.0.11.128, 00:15:4d:0b:80:0b 89 | 10.0.241.166, 00:15:4d:f1:a6:f5 90 | 10.0.250.72, 00:15:4d:fa:48:73 91 | 10.0.22.29, 00:15:4d:16:1d:bc 92 | 10.0.181.193, 00:15:4d:b5:c1:87 93 | 10.0.92.78, 00:15:4d:5c:4e:ee 94 | 10.0.95.136, 00:15:4d:5f:88:a9 95 | 10.0.90.99, 00:15:4d:5a:63:f8 96 | 10.0.148.153, 00:15:4d:94:99:c9 97 | 10.0.93.121, 00:15:4d:5d:79:0f 98 | 10.0.163.157, 00:15:4d:a3:9d:50 99 | 10.0.95.55, 00:15:4d:5f:37:1f 100 | 10.0.32.37, 00:15:4d:20:25:1f 101 | 10.0.10.129, 00:15:4d:0a:81:6b 102 | 10.0.125.0, 00:15:4d:7d:00:64 103 | 10.0.90.54, 00:15:4d:5a:36:2b 104 | 10.0.90.92, 00:15:4d:5a:5c:65 105 | 10.0.186.52, 00:15:4d:ba:34:12 106 | 10.0.226.220, 00:15:4d:e2:dc:37 107 | 10.0.11.231, 00:15:4d:0b:e7:73 108 | 10.0.158.164, 00:15:4d:9e:a4:23 109 | 10.0.56.200, 00:15:4d:38:c8:90 110 | 10.0.201.210, 00:15:4d:c9:d2:e0 111 | 10.0.107.116, 00:15:4d:6b:74:3c 112 | 10.0.117.250, 00:15:4d:75:fa:30 113 | 10.0.57.172, 00:15:4d:39:ac:b7 114 | 10.0.222.139, 00:15:4d:de:8b:19 115 | 10.0.13.222, 00:15:4d:0d:de:06 116 | 10.0.179.42, 00:15:4d:b3:2a:66 117 | 10.0.223.214, 00:15:4d:df:d6:9c 118 | 10.0.238.67, 00:15:4d:ee:43:df 119 | 10.0.234.248, 00:15:4d:ea:f8:48 120 | 10.0.106.113, 00:15:4d:6a:71:a6 121 | 10.0.2.228, 00:15:4d:02:e4:81 122 | 10.0.48.179, 00:15:4d:30:b3:bb 123 | 10.0.179.135, 00:15:4d:b3:87:64 124 | 10.0.249.63, 00:15:4d:f9:3f:8b 125 | 10.0.27.194, 00:15:4d:1b:c2:14 126 | 10.0.68.55, 00:15:4d:44:37:d0 127 | 10.0.20.7, 00:15:4d:14:07:8c 128 | 10.0.134.42, 00:15:4d:86:2a:97 129 | -------------------------------------------------------------------------------- /l4lb/destination_samples/256_destinations.csv: -------------------------------------------------------------------------------- 1 | 10.0.128.192, 00:15:4d:80:c0:f1 2 | 10.0.96.178, 00:15:4d:60:b2:77 3 | 10.0.239.127, 00:15:4d:ef:7f:12 4 | 10.0.211.136, 00:15:4d:d3:88:b0 5 | 10.0.55.164, 00:15:4d:37:a4:34 6 | 10.0.189.181, 00:15:4d:bd:b5:ed 7 | 10.0.87.208, 00:15:4d:57:d0:d4 8 | 10.0.32.185, 00:15:4d:20:b9:ed 9 | 10.0.166.207, 00:15:4d:a6:cf:c8 10 | 10.0.11.243, 00:15:4d:0b:f3:7e 11 | 10.0.88.196, 00:15:4d:58:c4:cf 12 | 10.0.154.213, 00:15:4d:9a:d5:10 13 | 10.0.7.163, 00:15:4d:07:a3:86 14 | 10.0.160.228, 00:15:4d:a0:e4:f4 15 | 10.0.76.250, 00:15:4d:4c:fa:38 16 | 10.0.46.174, 00:15:4d:2e:ae:cf 17 | 10.0.40.103, 00:15:4d:28:67:72 18 | 10.0.198.22, 00:15:4d:c6:16:72 19 | 10.0.25.200, 00:15:4d:19:c8:7f 20 | 10.0.219.121, 00:15:4d:db:79:67 21 | 10.0.202.8, 00:15:4d:ca:08:12 22 | 10.0.177.221, 00:15:4d:b1:dd:4f 23 | 10.0.146.225, 00:15:4d:92:e1:87 24 | 10.0.33.182, 00:15:4d:21:b6:67 25 | 10.0.5.40, 00:15:4d:05:28:96 26 | 10.0.167.116, 00:15:4d:a7:74:86 27 | 10.0.72.188, 00:15:4d:48:bc:c9 28 | 10.0.20.135, 00:15:4d:14:87:73 29 | 10.0.82.123, 00:15:4d:52:7b:7e 30 | 10.0.244.235, 00:15:4d:f4:eb:a1 31 | 10.0.6.154, 00:15:4d:06:9a:6b 32 | 10.0.69.98, 00:15:4d:45:62:19 33 | 10.0.54.169, 00:15:4d:36:a9:0d 34 | 10.0.0.14, 00:15:4d:00:0e:71 35 | 10.0.45.244, 00:15:4d:2d:f4:5c 36 | 10.0.109.138, 00:15:4d:6d:8a:a0 37 | 10.0.38.41, 00:15:4d:26:29:bb 38 | 10.0.158.7, 00:15:4d:9e:07:f7 39 | 10.0.43.23, 00:15:4d:2b:17:60 40 | 10.0.124.78, 00:15:4d:7c:4e:30 41 | 10.0.139.197, 00:15:4d:8b:c5:1d 42 | 10.0.144.16, 00:15:4d:90:10:89 43 | 10.0.187.199, 00:15:4d:bb:c7:65 44 | 10.0.72.66, 00:15:4d:48:42:bd 45 | 10.0.68.224, 00:15:4d:44:e0:04 46 | 10.0.138.44, 00:15:4d:8a:2c:e4 47 | 10.0.214.119, 00:15:4d:d6:77:80 48 | 10.0.126.135, 00:15:4d:7e:87:5c 49 | 10.0.232.141, 00:15:4d:e8:8d:13 50 | 10.0.192.72, 00:15:4d:c0:48:e7 51 | 10.0.223.209, 00:15:4d:df:d1:6b 52 | 10.0.10.140, 00:15:4d:0a:8c:04 53 | 10.0.152.163, 00:15:4d:98:a3:df 54 | 10.0.230.94, 00:15:4d:e6:5e:95 55 | 10.0.82.48, 00:15:4d:52:30:ec 56 | 10.0.217.198, 00:15:4d:d9:c6:35 57 | 10.0.11.61, 00:15:4d:0b:3d:f8 58 | 10.0.206.111, 00:15:4d:ce:6f:82 59 | 10.0.192.56, 00:15:4d:c0:38:91 60 | 10.0.33.205, 00:15:4d:21:cd:7d 61 | 10.0.232.230, 00:15:4d:e8:e6:07 62 | 10.0.71.148, 00:15:4d:47:94:60 63 | 10.0.172.38, 00:15:4d:ac:26:83 64 | 10.0.81.78, 00:15:4d:51:4e:d1 65 | 10.0.52.216, 00:15:4d:34:d8:20 66 | 10.0.102.62, 00:15:4d:66:3e:8e 67 | 10.0.102.83, 00:15:4d:66:53:aa 68 | 10.0.131.31, 00:15:4d:83:1f:26 69 | 10.0.87.161, 00:15:4d:57:a1:2d 70 | 10.0.63.138, 00:15:4d:3f:8a:99 71 | 10.0.151.7, 00:15:4d:97:07:16 72 | 10.0.194.195, 00:15:4d:c2:c3:9a 73 | 10.0.53.62, 00:15:4d:35:3e:79 74 | 10.0.253.245, 00:15:4d:fd:f5:5f 75 | 10.0.47.229, 00:15:4d:2f:e5:cb 76 | 10.0.209.139, 00:15:4d:d1:8b:44 77 | 10.0.24.212, 00:15:4d:18:d4:78 78 | 10.0.130.236, 00:15:4d:82:ec:da 79 | 10.0.168.214, 00:15:4d:a8:d6:15 80 | 10.0.92.44, 00:15:4d:5c:2c:dc 81 | 10.0.237.23, 00:15:4d:ed:17:80 82 | 10.0.232.87, 00:15:4d:e8:57:ad 83 | 10.0.14.93, 00:15:4d:0e:5d:34 84 | 10.0.32.144, 00:15:4d:20:90:34 85 | 10.0.137.63, 00:15:4d:89:3f:61 86 | 10.0.198.84, 00:15:4d:c6:54:4f 87 | 10.0.233.119, 00:15:4d:e9:77:a5 88 | 10.0.102.71, 00:15:4d:66:47:58 89 | 10.0.52.238, 00:15:4d:34:ee:2d 90 | 10.0.22.167, 00:15:4d:16:a7:8c 91 | 10.0.66.62, 00:15:4d:42:3e:57 92 | 10.0.228.217, 00:15:4d:e4:d9:4b 93 | 10.0.187.180, 00:15:4d:bb:b4:49 94 | 10.0.127.118, 00:15:4d:7f:9e:0a 95 | 10.0.249.242, 00:15:4d:f9:f2:ac 96 | 10.0.91.117, 00:15:4d:5b:75:67 97 | 10.0.113.105, 00:15:4d:71:69:b0 98 | 10.0.122.65, 00:15:4d:7a:41:b9 99 | 10.0.128.99, 00:15:4d:80:63:15 100 | 10.0.120.15, 00:15:4d:78:0f:6b 101 | 10.0.193.21, 00:15:4d:c1:15:7d 102 | 10.0.238.226, 00:15:4d:ee:e2:b6 103 | 10.0.15.155, 00:15:4d:0f:9b:92 104 | 10.0.70.112, 00:15:4d:46:70:85 105 | 10.0.183.249, 00:15:4d:b7:f9:3f 106 | 10.0.19.39, 00:15:4d:13:27:e0 107 | 10.0.192.234, 00:15:4d:c0:ea:40 108 | 10.0.2.130, 00:15:4d:02:82:17 109 | 10.0.213.214, 00:15:4d:d5:d6:be 110 | 10.0.221.60, 00:15:4d:dd:3c:bd 111 | 10.0.124.225, 00:15:4d:7c:e1:75 112 | 10.0.17.29, 00:15:4d:11:1d:01 113 | 10.0.27.105, 00:15:4d:1b:69:6a 114 | 10.0.57.226, 00:15:4d:39:e2:7e 115 | 10.0.217.250, 00:15:4d:d9:fa:5c 116 | 10.0.111.82, 00:15:4d:6f:52:cd 117 | 10.0.126.126, 00:15:4d:7e:7e:34 118 | 10.0.20.130, 00:15:4d:14:82:17 119 | 10.0.87.156, 00:15:4d:57:9c:a1 120 | 10.0.207.63, 00:15:4d:cf:3f:c0 121 | 10.0.121.65, 00:15:4d:79:41:c4 122 | 10.0.149.155, 00:15:4d:95:9b:c4 123 | 10.0.19.174, 00:15:4d:13:ae:27 124 | 10.0.132.129, 00:15:4d:84:81:f6 125 | 10.0.92.248, 00:15:4d:5c:f8:8a 126 | 10.0.28.5, 00:15:4d:1c:05:8d 127 | 10.0.140.124, 00:15:4d:8c:7c:89 128 | 10.0.6.6, 00:15:4d:06:06:3c 129 | 10.0.70.136, 00:15:4d:46:88:67 130 | 10.0.203.195, 00:15:4d:cb:c3:95 131 | 10.0.230.202, 00:15:4d:e6:ca:c9 132 | 10.0.90.47, 00:15:4d:5a:2f:96 133 | 10.0.89.179, 00:15:4d:59:b3:b8 134 | 10.0.161.13, 00:15:4d:a1:0d:a7 135 | 10.0.0.208, 00:15:4d:00:d0:89 136 | 10.0.155.69, 00:15:4d:9b:45:b5 137 | 10.0.165.214, 00:15:4d:a5:d6:c1 138 | 10.0.35.186, 00:15:4d:23:ba:49 139 | 10.0.97.127, 00:15:4d:61:7f:76 140 | 10.0.136.252, 00:15:4d:88:fc:75 141 | 10.0.96.125, 00:15:4d:60:7d:0c 142 | 10.0.121.36, 00:15:4d:79:24:6f 143 | 10.0.37.187, 00:15:4d:25:bb:b5 144 | 10.0.4.6, 00:15:4d:04:06:b3 145 | 10.0.245.164, 00:15:4d:f5:a4:64 146 | 10.0.239.210, 00:15:4d:ef:d2:2e 147 | 10.0.55.27, 00:15:4d:37:1b:28 148 | 10.0.86.174, 00:15:4d:56:ae:79 149 | 10.0.134.50, 00:15:4d:86:32:e0 150 | 10.0.101.204, 00:15:4d:65:cc:83 151 | 10.0.237.57, 00:15:4d:ed:39:4f 152 | 10.0.57.209, 00:15:4d:39:d1:ce 153 | 10.0.146.250, 00:15:4d:92:fa:a3 154 | 10.0.119.232, 00:15:4d:77:e8:9d 155 | 10.0.85.15, 00:15:4d:55:0f:19 156 | 10.0.180.61, 00:15:4d:b4:3d:7a 157 | 10.0.146.83, 00:15:4d:92:53:ca 158 | 10.0.166.74, 00:15:4d:a6:4a:91 159 | 10.0.216.47, 00:15:4d:d8:2f:aa 160 | 10.0.168.1, 00:15:4d:a8:01:cf 161 | 10.0.230.23, 00:15:4d:e6:17:31 162 | 10.0.160.173, 00:15:4d:a0:ad:cf 163 | 10.0.199.92, 00:15:4d:c7:5c:0d 164 | 10.0.172.117, 00:15:4d:ac:75:7b 165 | 10.0.222.145, 00:15:4d:de:91:d4 166 | 10.0.202.187, 00:15:4d:ca:bb:8d 167 | 10.0.58.144, 00:15:4d:3a:90:55 168 | 10.0.127.158, 00:15:4d:7f:9e:a2 169 | 10.0.103.252, 00:15:4d:67:fc:c9 170 | 10.0.236.159, 00:15:4d:ec:9f:9c 171 | 10.0.21.75, 00:15:4d:15:4b:4a 172 | 10.0.84.174, 00:15:4d:54:ae:89 173 | 10.0.237.211, 00:15:4d:ed:d3:97 174 | 10.0.42.215, 00:15:4d:2a:d7:a2 175 | 10.0.161.77, 00:15:4d:a1:4d:15 176 | 10.0.200.22, 00:15:4d:c8:16:c9 177 | 10.0.225.119, 00:15:4d:e1:77:cc 178 | 10.0.191.81, 00:15:4d:bf:51:be 179 | 10.0.216.179, 00:15:4d:d8:b3:29 180 | 10.0.93.76, 00:15:4d:5d:4c:6f 181 | 10.0.169.90, 00:15:4d:a9:5a:85 182 | 10.0.64.189, 00:15:4d:40:bd:3d 183 | 10.0.91.155, 00:15:4d:5b:9b:67 184 | 10.0.78.130, 00:15:4d:4e:82:5d 185 | 10.0.33.95, 00:15:4d:21:5f:fd 186 | 10.0.126.140, 00:15:4d:7e:8c:3b 187 | 10.0.21.67, 00:15:4d:15:43:7b 188 | 10.0.221.142, 00:15:4d:dd:8e:2c 189 | 10.0.169.5, 00:15:4d:a9:05:67 190 | 10.0.167.45, 00:15:4d:a7:2d:78 191 | 10.0.160.190, 00:15:4d:a0:be:7a 192 | 10.0.234.5, 00:15:4d:ea:05:4e 193 | 10.0.84.135, 00:15:4d:54:87:50 194 | 10.0.184.95, 00:15:4d:b8:5f:bb 195 | 10.0.165.206, 00:15:4d:a5:ce:43 196 | 10.0.199.194, 00:15:4d:c7:c2:25 197 | 10.0.27.212, 00:15:4d:1b:d4:4b 198 | 10.0.200.251, 00:15:4d:c8:fb:a3 199 | 10.0.205.148, 00:15:4d:cd:94:b6 200 | 10.0.1.126, 00:15:4d:01:7e:4b 201 | 10.0.3.62, 00:15:4d:03:3e:37 202 | 10.0.218.217, 00:15:4d:da:d9:7b 203 | 10.0.198.133, 00:15:4d:c6:85:49 204 | 10.0.16.236, 00:15:4d:10:ec:30 205 | 10.0.234.222, 00:15:4d:ea:de:b2 206 | 10.0.253.132, 00:15:4d:fd:84:f5 207 | 10.0.132.30, 00:15:4d:84:1e:9f 208 | 10.0.143.171, 00:15:4d:8f:ab:03 209 | 10.0.71.83, 00:15:4d:47:53:c6 210 | 10.0.58.71, 00:15:4d:3a:47:46 211 | 10.0.233.90, 00:15:4d:e9:5a:5d 212 | 10.0.189.106, 00:15:4d:bd:6a:0c 213 | 10.0.121.16, 00:15:4d:79:10:78 214 | 10.0.128.90, 00:15:4d:80:5a:c9 215 | 10.0.58.48, 00:15:4d:3a:30:bc 216 | 10.0.57.73, 00:15:4d:39:49:c5 217 | 10.0.108.135, 00:15:4d:6c:87:c0 218 | 10.0.196.63, 00:15:4d:c4:3f:82 219 | 10.0.1.107, 00:15:4d:01:6b:50 220 | 10.0.57.28, 00:15:4d:39:1c:b4 221 | 10.0.188.212, 00:15:4d:bc:d4:d1 222 | 10.0.165.35, 00:15:4d:a5:23:77 223 | 10.0.25.98, 00:15:4d:19:62:c1 224 | 10.0.189.132, 00:15:4d:bd:84:84 225 | 10.0.104.132, 00:15:4d:68:84:bd 226 | 10.0.86.48, 00:15:4d:56:30:10 227 | 10.0.21.186, 00:15:4d:15:ba:d5 228 | 10.0.169.205, 00:15:4d:a9:cd:5c 229 | 10.0.163.38, 00:15:4d:a3:26:65 230 | 10.0.46.226, 00:15:4d:2e:e2:00 231 | 10.0.77.208, 00:15:4d:4d:d0:96 232 | 10.0.103.157, 00:15:4d:67:9d:de 233 | 10.0.168.42, 00:15:4d:a8:2a:e9 234 | 10.0.28.203, 00:15:4d:1c:cb:17 235 | 10.0.169.159, 00:15:4d:a9:9f:f2 236 | 10.0.83.227, 00:15:4d:53:e3:4a 237 | 10.0.102.227, 00:15:4d:66:e3:37 238 | 10.0.177.228, 00:15:4d:b1:e4:d5 239 | 10.0.150.123, 00:15:4d:96:7b:ec 240 | 10.0.178.155, 00:15:4d:b2:9b:84 241 | 10.0.136.160, 00:15:4d:88:a0:fe 242 | 10.0.124.147, 00:15:4d:7c:93:b8 243 | 10.0.252.201, 00:15:4d:fc:c9:be 244 | 10.0.126.29, 00:15:4d:7e:1d:0c 245 | 10.0.146.116, 00:15:4d:92:74:22 246 | 10.0.164.177, 00:15:4d:a4:b1:ef 247 | 10.0.114.234, 00:15:4d:72:ea:83 248 | 10.0.226.20, 00:15:4d:e2:14:c4 249 | 10.0.28.135, 00:15:4d:1c:87:54 250 | 10.0.182.104, 00:15:4d:b6:68:7b 251 | 10.0.101.8, 00:15:4d:65:08:af 252 | 10.0.86.119, 00:15:4d:56:77:4a 253 | 10.0.159.173, 00:15:4d:9f:ad:ee 254 | 10.0.153.183, 00:15:4d:99:b7:ac 255 | 10.0.91.173, 00:15:4d:5b:ad:04 256 | 10.0.230.48, 00:15:4d:e6:30:86 257 | -------------------------------------------------------------------------------- /l4lb/destination_samples/32_destinations.csv: -------------------------------------------------------------------------------- 1 | 10.0.89.127, 00:15:4d:59:7f:ad 2 | 10.0.214.65, 00:15:4d:d6:41:bd 3 | 10.0.178.75, 00:15:4d:b2:4b:c8 4 | 10.0.24.77, 00:15:4d:18:4d:d8 5 | 10.0.199.54, 00:15:4d:c7:36:9f 6 | 10.0.234.48, 00:15:4d:ea:30:28 7 | 10.0.175.130, 00:15:4d:af:82:8c 8 | 10.0.244.158, 00:15:4d:f4:9e:b3 9 | 10.0.185.52, 00:15:4d:b9:34:6d 10 | 10.0.159.176, 00:15:4d:9f:b0:37 11 | 10.0.125.19, 00:15:4d:7d:13:9f 12 | 10.0.56.49, 00:15:4d:38:31:6f 13 | 10.0.75.197, 00:15:4d:4b:c5:1f 14 | 10.0.75.209, 00:15:4d:4b:d1:a9 15 | 10.0.92.11, 00:15:4d:5c:0b:d3 16 | 10.0.31.144, 00:15:4d:1f:90:cb 17 | 10.0.32.134, 00:15:4d:20:86:6c 18 | 10.0.50.179, 00:15:4d:32:b3:09 19 | 10.0.0.57, 00:15:4d:00:39:c4 20 | 10.0.16.109, 00:15:4d:10:6d:cf 21 | 10.0.192.32, 00:15:4d:c0:20:d2 22 | 10.0.90.135, 00:15:4d:5a:87:1e 23 | 10.0.75.126, 00:15:4d:4b:7e:c4 24 | 10.0.63.10, 00:15:4d:3f:0a:ae 25 | 10.0.161.129, 00:15:4d:a1:81:9f 26 | 10.0.129.60, 00:15:4d:81:3c:5e 27 | 10.0.143.99, 00:15:4d:8f:63:5c 28 | 10.0.32.35, 00:15:4d:20:23:a7 29 | 10.0.14.88, 00:15:4d:0e:58:7a 30 | 10.0.23.41, 00:15:4d:17:29:ae 31 | 10.0.90.214, 00:15:4d:5a:d6:d0 32 | 10.0.181.34, 00:15:4d:b5:22:c3 33 | -------------------------------------------------------------------------------- /l4lb/destination_samples/512_destinations.csv: -------------------------------------------------------------------------------- 1 | 10.0.212.70, 00:15:4d:d4:46:8f 2 | 10.0.47.219, 00:15:4d:2f:db:39 3 | 10.0.68.55, 00:15:4d:44:37:3d 4 | 10.0.214.11, 00:15:4d:d6:0b:f3 5 | 10.0.160.168, 00:15:4d:a0:a8:b0 6 | 10.0.106.197, 00:15:4d:6a:c5:04 7 | 10.0.250.85, 00:15:4d:fa:55:37 8 | 10.0.207.173, 00:15:4d:cf:ad:f0 9 | 10.0.56.197, 00:15:4d:38:c5:8a 10 | 10.0.226.152, 00:15:4d:e2:98:e1 11 | 10.0.58.44, 00:15:4d:3a:2c:f5 12 | 10.0.229.45, 00:15:4d:e5:2d:0d 13 | 10.0.187.142, 00:15:4d:bb:8e:64 14 | 10.0.24.34, 00:15:4d:18:22:4f 15 | 10.0.166.54, 00:15:4d:a6:36:ae 16 | 10.0.93.206, 00:15:4d:5d:ce:db 17 | 10.0.231.249, 00:15:4d:e7:f9:1f 18 | 10.0.65.76, 00:15:4d:41:4c:26 19 | 10.0.15.234, 00:15:4d:0f:ea:c3 20 | 10.0.230.55, 00:15:4d:e6:37:15 21 | 10.0.136.86, 00:15:4d:88:56:03 22 | 10.0.148.53, 00:15:4d:94:35:2f 23 | 10.0.183.116, 00:15:4d:b7:74:16 24 | 10.0.180.50, 00:15:4d:b4:32:33 25 | 10.0.254.80, 00:15:4d:fe:50:28 26 | 10.0.233.102, 00:15:4d:e9:66:26 27 | 10.0.102.227, 00:15:4d:66:e3:67 28 | 10.0.113.54, 00:15:4d:71:36:c4 29 | 10.0.40.225, 00:15:4d:2b:e1:86 30 | 10.0.88.87, 00:15:4d:58:57:67 31 | 10.0.175.163, 00:15:4d:af:a3:e5 32 | 10.0.9.218, 00:15:4d:09:da:d5 33 | 10.0.40.86, 00:15:4d:28:56:cf 34 | 10.0.75.65, 00:15:4d:4b:41:df 35 | 10.0.250.93, 00:15:4d:fa:5d:c8 36 | 10.0.56.38, 00:15:4d:38:26:4c 37 | 10.0.206.8, 00:15:4d:ce:08:a6 38 | 10.0.196.245, 00:15:4d:c4:f5:0d 39 | 10.0.186.51, 00:15:4d:ba:33:9e 40 | 10.0.145.16, 00:15:4d:91:10:4e 41 | 10.0.186.6, 00:15:4d:ba:06:41 42 | 10.0.72.74, 00:15:4d:48:4a:95 43 | 10.0.88.233, 00:15:4d:58:e9:40 44 | 10.0.170.57, 00:15:4d:aa:39:19 45 | 10.0.174.71, 00:15:4d:ae:47:83 46 | 10.0.205.107, 00:15:4d:cd:6b:ca 47 | 10.0.167.246, 00:15:4d:a7:f6:ed 48 | 10.0.174.232, 00:15:4d:ae:e8:2b 49 | 10.0.168.32, 00:15:4d:a8:20:53 50 | 10.0.224.43, 00:15:4d:e0:2b:c7 51 | 10.0.93.164, 00:15:4d:5d:a4:8f 52 | 10.0.158.161, 00:15:4d:9e:a1:32 53 | 10.0.181.253, 00:15:4d:b5:fd:fc 54 | 10.0.207.193, 00:15:4d:cf:c1:d1 55 | 10.0.156.0, 00:15:4d:9c:00:95 56 | 10.0.120.164, 00:15:4d:78:a6:04 57 | 10.0.165.105, 00:15:4d:a5:69:9d 58 | 10.0.145.130, 00:15:4d:91:82:26 59 | 10.0.171.20, 00:15:4d:ab:14:9f 60 | 10.0.68.20, 00:15:4d:44:14:bd 61 | 10.0.82.179, 00:15:4d:52:b3:32 62 | 10.0.248.39, 00:15:4d:f8:27:2d 63 | 10.0.168.14, 00:15:4d:a8:0e:66 64 | 10.0.195.102, 00:15:4d:c3:66:c8 65 | 10.0.165.167, 00:15:4d:a5:a7:39 66 | 10.0.176.113, 00:15:4d:b0:71:f8 67 | 10.0.120.227, 00:15:4d:78:e3:0b 68 | 10.0.219.90, 00:15:4d:db:5a:7e 69 | 10.0.178.140, 00:15:4d:b2:8c:40 70 | 10.0.59.79, 00:15:4d:3b:4f:44 71 | 10.0.158.189, 00:15:4d:9e:bd:d3 72 | 10.0.40.70, 00:15:4d:28:46:34 73 | 10.0.225.152, 00:15:4d:e1:98:a9 74 | 10.0.36.165, 00:15:4d:24:a5:82 75 | 10.0.94.93, 00:15:4d:5e:5d:15 76 | 10.0.83.128, 00:15:4d:53:80:4f 77 | 10.0.76.13, 00:15:4d:4c:0d:ec 78 | 10.0.118.86, 00:15:4d:76:56:f4 79 | 10.0.176.235, 00:15:4d:b0:eb:75 80 | 10.0.188.233, 00:15:4d:bc:e9:d8 81 | 10.0.202.241, 00:15:4d:ca:f1:ee 82 | 10.0.37.168, 00:15:4d:25:a8:1f 83 | 10.0.195.176, 00:15:4d:c3:b0:59 84 | 10.0.65.57, 00:15:4d:41:39:f6 85 | 10.0.221.4, 00:15:4d:dd:04:44 86 | 10.0.44.138, 00:15:4d:2c:8a:39 87 | 10.0.142.65, 00:15:4d:8e:41:43 88 | 10.0.88.84, 00:15:4d:58:54:bd 89 | 10.0.163.174, 00:15:4d:a3:ae:5a 90 | 10.0.199.94, 00:15:4d:c7:5e:9e 91 | 10.0.219.201, 00:15:4d:db:c9:3e 92 | 10.0.26.231, 00:15:4d:1a:e7:12 93 | 10.0.43.225, 00:15:4d:2b:e1:73 94 | 10.0.160.35, 00:15:4d:a0:23:fe 95 | 10.0.92.199, 00:15:4d:5c:c7:9d 96 | 10.0.120.114, 00:15:4d:78:72:46 97 | 10.0.253.62, 00:15:4d:fd:3e:dd 98 | 10.0.135.200, 00:15:4d:87:c8:4e 99 | 10.0.92.114, 00:15:4d:5c:72:8e 100 | 10.0.219.222, 00:15:4d:db:de:92 101 | 10.0.154.138, 00:15:4d:9a:8a:b3 102 | 10.0.167.68, 00:15:4d:a7:44:8a 103 | 10.0.231.143, 00:15:4d:e7:8f:c3 104 | 10.0.237.28, 00:15:4d:ed:1c:eb 105 | 10.0.226.243, 00:15:4d:e2:f3:60 106 | 10.0.8.3, 00:15:4d:08:03:b8 107 | 10.0.52.35, 00:15:4d:34:23:c0 108 | 10.0.175.212, 00:15:4d:af:d4:84 109 | 10.0.184.67, 00:15:4d:b8:43:33 110 | 10.0.147.13, 00:15:4d:93:0d:36 111 | 10.0.222.50, 00:15:4d:de:32:69 112 | 10.0.1.222, 00:15:4d:01:de:bb 113 | 10.0.74.63, 00:15:4d:4a:3f:bd 114 | 10.0.194.127, 00:15:4d:c2:7f:b4 115 | 10.0.99.66, 00:15:4d:63:42:df 116 | 10.0.10.74, 00:15:4d:0a:4a:b7 117 | 10.0.253.143, 00:15:4d:fd:8f:b1 118 | 10.0.44.2, 00:15:4d:2c:02:cd 119 | 10.0.3.250, 00:15:4d:03:fe:13 120 | 10.0.114.169, 00:15:4d:72:a9:1c 121 | 10.0.133.177, 00:15:4d:85:b1:2b 122 | 10.0.189.77, 00:15:4d:bd:4d:fd 123 | 10.0.239.11, 00:15:4d:ef:0b:8a 124 | 10.0.203.91, 00:15:4d:cb:5b:f9 125 | 10.0.185.3, 00:15:4d:b9:03:55 126 | 10.0.251.239, 00:15:4d:fb:ef:fb 127 | 10.0.236.208, 00:15:4d:ec:d0:7a 128 | 10.0.231.78, 00:15:4d:e7:4e:a1 129 | 10.0.185.48, 00:15:4d:b9:30:88 130 | 10.0.62.14, 00:15:4d:3e:0e:fa 131 | 10.0.14.18, 00:15:4d:0e:12:8e 132 | 10.0.206.174, 00:15:4d:ce:ae:6b 133 | 10.0.26.17, 00:15:4d:1a:11:62 134 | 10.0.77.101, 00:15:4d:4d:65:d6 135 | 10.0.112.140, 00:15:4d:70:8c:4a 136 | 10.0.219.48, 00:15:4d:db:30:19 137 | 10.0.132.137, 00:15:4d:84:89:13 138 | 10.0.19.129, 00:15:4d:13:81:39 139 | 10.0.190.195, 00:15:4d:be:c3:2e 140 | 10.0.123.113, 00:15:4d:7b:71:ae 141 | 10.0.113.176, 00:15:4d:71:b0:24 142 | 10.0.171.218, 00:15:4d:ab:da:de 143 | 10.0.120.166, 00:15:4d:78:a6:6c 144 | 10.0.76.254, 00:15:4d:4c:fe:5e 145 | 10.0.38.73, 00:15:4d:26:49:c5 146 | 10.0.86.85, 00:15:4d:56:55:52 147 | 10.0.19.189, 00:15:4d:13:bd:8f 148 | 10.0.55.21, 00:15:4d:37:15:13 149 | 10.0.99.239, 00:15:4d:63:ef:a5 150 | 10.0.191.51, 00:15:4d:bf:33:f8 151 | 10.0.249.221, 00:15:4d:f9:dd:40 152 | 10.0.239.35, 00:15:4d:ef:23:52 153 | 10.0.247.191, 00:15:4d:f7:bf:05 154 | 10.0.5.139, 00:15:4d:05:8b:3c 155 | 10.0.16.140, 00:15:4d:10:8c:a6 156 | 10.0.247.85, 00:15:4d:f7:55:53 157 | 10.0.202.235, 00:15:4d:ca:eb:a7 158 | 10.0.8.55, 00:15:4d:08:37:37 159 | 10.0.127.137, 00:15:4d:7f:89:ce 160 | 10.0.0.223, 00:15:4d:00:df:1e 161 | 10.0.89.25, 00:15:4d:59:19:fe 162 | 10.0.132.108, 00:15:4d:84:6c:a3 163 | 10.0.5.225, 00:15:4d:05:e1:ed 164 | 10.0.58.29, 00:15:4d:3a:1d:1e 165 | 10.0.8.205, 00:15:4d:08:cd:d4 166 | 10.0.105.65, 00:15:4d:69:41:4c 167 | 10.0.219.15, 00:15:4d:db:0f:c7 168 | 10.0.102.77, 00:15:4d:66:4d:90 169 | 10.0.97.50, 00:15:4d:61:32:35 170 | 10.0.167.214, 00:15:4d:a7:d6:29 171 | 10.0.13.176, 00:15:4d:0d:b0:f6 172 | 10.0.124.183, 00:15:4d:7c:b7:be 173 | 10.0.75.32, 00:15:4d:4b:20:8f 174 | 10.0.144.206, 00:15:4d:90:ce:cc 175 | 10.0.135.178, 00:15:4d:87:b2:3a 176 | 10.0.53.31, 00:15:4d:35:1f:c8 177 | 10.0.123.205, 00:15:4d:7b:cd:17 178 | 10.0.220.17, 00:15:4d:dc:11:b8 179 | 10.0.109.84, 00:15:4d:6d:54:d0 180 | 10.0.71.210, 00:15:4d:47:d2:ec 181 | 10.0.93.37, 00:15:4d:5d:25:1c 182 | 10.0.19.124, 00:15:4d:13:7c:b4 183 | 10.0.169.14, 00:15:4d:a9:0e:39 184 | 10.0.145.187, 00:15:4d:91:bb:dd 185 | 10.0.102.249, 00:15:4d:66:f9:ed 186 | 10.0.237.106, 00:15:4d:ed:6a:5b 187 | 10.0.55.84, 00:15:4d:37:54:a7 188 | 10.0.188.122, 00:15:4d:bc:7a:82 189 | 10.0.232.114, 00:15:4d:e8:72:f6 190 | 10.0.242.119, 00:15:4d:f2:77:4f 191 | 10.0.160.140, 00:15:4d:a0:8c:91 192 | 10.0.118.103, 00:15:4d:76:67:a3 193 | 10.0.22.206, 00:15:4d:16:ce:39 194 | 10.0.109.90, 00:15:4d:6d:5a:6c 195 | 10.0.142.196, 00:15:4d:8e:c4:65 196 | 10.0.35.181, 00:15:4d:23:b5:f0 197 | 10.0.99.62, 00:15:4d:63:3e:fc 198 | 10.0.32.79, 00:15:4d:20:4f:e7 199 | 10.0.189.14, 00:15:4d:bd:0e:0f 200 | 10.0.40.158, 00:15:4d:28:9e:6e 201 | 10.0.12.166, 00:15:4d:0c:a6:b5 202 | 10.0.25.39, 00:15:4d:19:27:5a 203 | 10.0.161.44, 00:15:4d:a1:2c:b6 204 | 10.0.89.203, 00:15:4d:59:cb:b2 205 | 10.0.67.183, 00:15:4d:43:b7:2c 206 | 10.0.110.191, 00:15:4d:6e:bf:80 207 | 10.0.81.247, 00:15:4d:51:f7:d1 208 | 10.0.77.229, 00:15:4d:4d:e5:57 209 | 10.0.178.19, 00:15:4d:b2:13:ae 210 | 10.0.204.89, 00:15:4d:cc:59:0f 211 | 10.0.30.0, 00:15:4d:1e:00:7b 212 | 10.0.148.51, 00:15:4d:94:33:4d 213 | 10.0.213.43, 00:15:4d:d5:2b:56 214 | 10.0.105.225, 00:15:4d:69:e1:31 215 | 10.0.150.197, 00:15:4d:96:c5:41 216 | 10.0.2.69, 00:15:4d:02:45:eb 217 | 10.0.0.135, 00:15:4d:00:87:4f 218 | 10.0.85.113, 00:15:4d:55:71:e1 219 | 10.0.132.23, 00:15:4d:84:17:28 220 | 10.0.14.185, 00:15:4d:0e:b9:f3 221 | 10.0.89.21, 00:15:4d:59:15:57 222 | 10.0.99.52, 00:15:4d:63:34:70 223 | 10.0.43.173, 00:15:4d:2b:ad:22 224 | 10.0.122.212, 00:15:4d:7a:d4:fd 225 | 10.0.106.106, 00:15:4d:6a:6a:f5 226 | 10.0.86.91, 00:15:4d:56:5b:cb 227 | 10.0.217.233, 00:15:4d:d9:e9:d0 228 | 10.0.195.226, 00:15:4d:c3:e2:58 229 | 10.0.79.46, 00:15:4d:4f:2e:6a 230 | 10.0.85.18, 00:15:4d:55:12:8c 231 | 10.0.213.194, 00:15:4d:d5:c2:76 232 | 10.0.4.188, 00:15:4d:04:bc:5a 233 | 10.0.237.180, 00:15:4d:ed:b4:1b 234 | 10.0.252.132, 00:15:4d:fc:84:34 235 | 10.0.128.254, 00:15:4d:80:fe:42 236 | 10.0.228.232, 00:15:4d:e4:e8:d2 237 | 10.0.168.106, 00:15:4d:a8:6a:83 238 | 10.0.40.6, 00:15:4d:28:06:67 239 | 10.0.196.226, 00:15:4d:c4:e2:96 240 | 10.0.170.161, 00:15:4d:aa:a1:7f 241 | 10.0.40.189, 00:15:4d:28:bd:48 242 | 10.0.53.194, 00:15:4d:35:c2:db 243 | 10.0.87.236, 00:15:4d:57:ec:33 244 | 10.0.44.224, 00:15:4d:2c:e0:db 245 | 10.0.207.53, 00:15:4d:cf:35:7b 246 | 10.0.68.76, 00:15:4d:44:4c:b2 247 | 10.0.132.145, 00:15:4d:84:91:4a 248 | 10.0.25.139, 00:15:4d:19:8b:2b 249 | 10.0.67.154, 00:15:4d:43:9a:6e 250 | 10.0.103.66, 00:15:4d:67:42:66 251 | 10.0.39.134, 00:15:4d:27:86:4f 252 | 10.0.43.223, 00:15:4d:2b:df:ce 253 | 10.0.198.164, 00:15:4d:c6:a4:ba 254 | 10.0.177.27, 00:15:4d:b1:1b:88 255 | 10.0.251.73, 00:15:4d:fb:49:c7 256 | 10.0.186.213, 00:15:4d:ba:d5:a7 257 | 10.0.34.102, 00:15:4d:22:66:b4 258 | 10.0.135.108, 00:15:4d:87:6c:5c 259 | 10.0.98.20, 00:15:4d:62:14:aa 260 | 10.0.113.179, 00:15:4d:71:b3:7b 261 | 10.0.110.135, 00:15:4d:6e:87:01 262 | 10.0.131.15, 00:15:4d:83:0f:ea 263 | 10.0.3.254, 00:15:4d:03:fe:57 264 | 10.0.168.63, 00:15:4d:a8:3f:17 265 | 10.0.124.178, 00:15:4d:7c:b2:dd 266 | 10.0.185.87, 00:15:4d:b9:57:97 267 | 10.0.112.208, 00:15:4d:70:d0:ad 268 | 10.0.113.94, 00:15:4d:71:5e:af 269 | 10.0.129.153, 00:15:4d:81:99:5b 270 | 10.0.48.197, 00:15:4d:30:c5:c4 271 | 10.0.25.15, 00:15:4d:19:0f:62 272 | 10.0.54.242, 00:15:4d:36:f2:19 273 | 10.0.251.68, 00:15:4d:fb:44:da 274 | 10.0.167.196, 00:15:4d:a7:c4:5a 275 | 10.0.105.214, 00:15:4d:69:d6:b1 276 | 10.0.100.134, 00:15:4d:64:86:8d 277 | 10.0.228.199, 00:15:4d:e4:c7:09 278 | 10.0.82.46, 00:15:4d:52:2e:83 279 | 10.0.58.164, 00:15:4d:3a:a4:05 280 | 10.0.60.204, 00:15:4d:3c:cc:cd 281 | 10.0.171.150, 00:15:4d:ab:96:af 282 | 10.0.182.61, 00:15:4d:b6:3d:33 283 | 10.0.100.183, 00:15:4d:64:b7:ad 284 | 10.0.239.85, 00:15:4d:ef:55:53 285 | 10.0.53.14, 00:15:4d:35:0e:14 286 | 10.0.56.113, 00:15:4d:38:71:c8 287 | 10.0.100.143, 00:15:4d:64:8f:54 288 | 10.0.243.248, 00:15:4d:f3:f8:02 289 | 10.0.92.90, 00:15:4d:5c:5a:1c 290 | 10.0.51.144, 00:15:4d:33:90:44 291 | 10.0.79.214, 00:15:4d:4f:d6:7f 292 | 10.0.151.85, 00:15:4d:97:55:a6 293 | 10.0.207.40, 00:15:4d:cf:28:28 294 | 10.0.103.109, 00:15:4d:67:6d:15 295 | 10.0.9.131, 00:15:4d:09:83:6b 296 | 10.0.50.245, 00:15:4d:32:f5:bf 297 | 10.0.81.211, 00:15:4d:51:d3:81 298 | 10.0.185.21, 00:15:4d:b9:15:26 299 | 10.0.83.173, 00:15:4d:53:ad:71 300 | 10.0.72.140, 00:15:4d:48:8c:1c 301 | 10.0.79.150, 00:15:4d:4f:96:0d 302 | 10.0.158.190, 00:15:4d:9e:be:4d 303 | 10.0.180.72, 00:15:4d:b4:48:9d 304 | 10.0.23.181, 00:15:4d:17:b5:0b 305 | 10.0.1.232, 00:15:4d:01:e8:1b 306 | 10.0.153.111, 00:15:4d:99:6f:31 307 | 10.0.218.135, 00:15:4d:da:87:06 308 | 10.0.253.85, 00:15:4d:fd:55:49 309 | 10.0.143.64, 00:15:4d:8f:40:05 310 | 10.0.16.146, 00:15:4d:10:92:ca 311 | 10.0.16.16, 00:15:4d:10:10:8a 312 | 10.0.79.100, 00:15:4d:4f:64:e3 313 | 10.0.44.54, 00:15:4d:2c:36:6a 314 | 10.0.191.185, 00:15:4d:bf:b9:83 315 | 10.0.245.194, 00:15:4d:f5:c2:a2 316 | 10.0.168.84, 00:15:4d:a8:54:14 317 | 10.0.103.162, 00:15:4d:67:a2:2b 318 | 10.0.96.176, 00:15:4d:60:b0:8d 319 | 10.0.135.33, 00:15:4d:87:21:52 320 | 10.0.192.144, 00:15:4d:c0:90:53 321 | 10.0.122.33, 00:15:4d:7a:21:38 322 | 10.0.220.42, 00:15:4d:dc:2a:52 323 | 10.0.137.134, 00:15:4d:89:86:94 324 | 10.0.3.129, 00:15:4d:03:81:ea 325 | 10.0.125.118, 00:15:4d:7d:76:9d 326 | 10.0.86.111, 00:15:4d:56:6f:6c 327 | 10.0.62.129, 00:15:4d:3e:81:68 328 | 10.0.65.218, 00:15:4d:41:da:7e 329 | 10.0.122.65, 00:15:4d:7a:41:0b 330 | 10.0.91.117, 00:15:4d:5b:75:a1 331 | 10.0.79.140, 00:15:4d:4f:8c:a4 332 | 10.0.161.205, 00:15:4d:a1:cd:15 333 | 10.0.110.186, 00:15:4d:6e:ba:66 334 | 10.0.107.6, 00:15:4d:6b:06:79 335 | 10.0.249.132, 00:15:4d:f9:84:ec 336 | 10.0.42.84, 00:15:4d:2a:54:10 337 | 10.0.210.142, 00:15:4d:d2:8e:0c 338 | 10.0.205.123, 00:15:4d:cd:7b:a4 339 | 10.0.12.122, 00:15:4d:0c:7a:d2 340 | 10.0.149.177, 00:15:4d:95:b1:51 341 | 10.0.167.49, 00:15:4d:a7:31:62 342 | 10.0.6.59, 00:15:4d:06:3b:33 343 | 10.0.63.239, 00:15:4d:3f:ef:40 344 | 10.0.128.241, 00:15:4d:80:f1:be 345 | 10.0.52.202, 00:15:4d:34:ca:06 346 | 10.0.240.205, 00:15:4d:f0:cd:42 347 | 10.0.228.221, 00:15:4d:e4:dd:f6 348 | 10.0.234.90, 00:15:4d:ea:5a:09 349 | 10.0.81.203, 00:15:4d:51:cb:12 350 | 10.0.170.147, 00:15:4d:aa:93:b7 351 | 10.0.223.175, 00:15:4d:df:af:86 352 | 10.0.246.221, 00:15:4d:f6:dd:70 353 | 10.0.196.31, 00:15:4d:c4:1f:32 354 | 10.0.1.40, 00:15:4d:01:28:48 355 | 10.0.97.220, 00:15:4d:61:dc:28 356 | 10.0.248.112, 00:15:4d:f8:70:d0 357 | 10.0.87.205, 00:15:4d:57:cd:e1 358 | 10.0.160.95, 00:15:4d:a0:5f:bc 359 | 10.0.185.69, 00:15:4d:b9:45:3f 360 | 10.0.204.194, 00:15:4d:cc:c2:76 361 | 10.0.48.123, 00:15:4d:30:7b:5e 362 | 10.0.103.27, 00:15:4d:67:1b:51 363 | 10.0.29.131, 00:15:4d:1d:83:79 364 | 10.0.39.185, 00:15:4d:27:b9:50 365 | 10.0.74.136, 00:15:4d:4a:88:17 366 | 10.0.173.112, 00:15:4d:ad:70:19 367 | 10.0.88.173, 00:15:4d:58:ad:5e 368 | 10.0.203.15, 00:15:4d:cb:0f:ae 369 | 10.0.11.122, 00:15:4d:0b:7a:41 370 | 10.0.148.58, 00:15:4d:94:3a:1c 371 | 10.0.236.123, 00:15:4d:ec:7b:99 372 | 10.0.101.95, 00:15:4d:65:5f:b3 373 | 10.0.185.218, 00:15:4d:b9:da:24 374 | 10.0.8.59, 00:15:4d:08:3b:88 375 | 10.0.172.55, 00:15:4d:ac:37:96 376 | 10.0.184.32, 00:15:4d:b8:20:a2 377 | 10.0.191.221, 00:15:4d:bf:dd:05 378 | 10.0.207.182, 00:15:4d:cf:b6:a4 379 | 10.0.115.120, 00:15:4d:73:78:62 380 | 10.0.46.33, 00:15:4d:2e:21:24 381 | 10.0.200.39, 00:15:4d:c8:27:89 382 | 10.0.41.185, 00:15:4d:29:b9:f4 383 | 10.0.83.242, 00:15:4d:53:f2:95 384 | 10.0.132.80, 00:15:4d:84:50:8a 385 | 10.0.16.221, 00:15:4d:10:dd:11 386 | 10.0.105.98, 00:15:4d:69:62:aa 387 | 10.0.205.125, 00:15:4d:cd:7d:a1 388 | 10.0.82.144, 00:15:4d:52:90:36 389 | 10.0.135.51, 00:15:4d:87:33:76 390 | 10.0.206.129, 00:15:4d:ce:81:fe 391 | 10.0.159.156, 00:15:4d:9f:9c:e1 392 | 10.0.152.36, 00:15:4d:98:24:a5 393 | 10.0.133.111, 00:15:4d:85:6f:b1 394 | 10.0.156.207, 00:15:4d:9c:cf:90 395 | 10.0.14.145, 00:15:4d:0e:91:c4 396 | 10.0.106.49, 00:15:4d:6a:31:55 397 | 10.0.10.184, 00:15:4d:0a:b8:89 398 | 10.0.68.115, 00:15:4d:44:73:7e 399 | 10.0.195.89, 00:15:4d:c3:59:34 400 | 10.0.43.111, 00:15:4d:2b:6f:09 401 | 10.0.73.101, 00:15:4d:49:65:84 402 | 10.0.179.181, 00:15:4d:b3:b5:a5 403 | 10.0.211.149, 00:15:4d:d3:95:af 404 | 10.0.40.212, 00:15:4d:28:d4:71 405 | 10.0.203.64, 00:15:4d:cb:40:eb 406 | 10.0.212.158, 00:15:4d:d4:9e:a6 407 | 10.0.173.114, 00:15:4d:ad:72:93 408 | 10.0.252.163, 00:15:4d:fc:a3:aa 409 | 10.0.250.41, 00:15:4d:fa:29:0e 410 | 10.0.247.142, 00:15:4d:f7:8e:60 411 | 10.0.27.73, 00:15:4d:1b:49:48 412 | 10.0.76.231, 00:15:4d:4c:e7:7e 413 | 10.0.124.124, 00:15:4d:7c:7c:73 414 | 10.0.86.88, 00:15:4d:56:58:e3 415 | 10.0.18.175, 00:15:4d:12:af:78 416 | 10.0.157.82, 00:15:4d:9d:52:5b 417 | 10.0.149.16, 00:15:4d:95:10:d7 418 | 10.0.183.176, 00:15:4d:b7:b0:83 419 | 10.0.192.110, 00:15:4d:c0:6e:70 420 | 10.0.139.55, 00:15:4d:8b:37:c3 421 | 10.0.206.27, 00:15:4d:ce:1b:a9 422 | 10.0.248.152, 00:15:4d:f8:98:06 423 | 10.0.118.176, 00:15:4d:76:b0:74 424 | 10.0.246.88, 00:15:4d:f6:58:25 425 | 10.0.161.3, 00:15:4d:a1:03:d3 426 | 10.0.132.208, 00:15:4d:84:d0:d5 427 | 10.0.100.185, 00:15:4d:64:b9:28 428 | 10.0.51.191, 00:15:4d:33:bf:a2 429 | 10.0.15.149, 00:15:4d:0f:95:8d 430 | 10.0.196.197, 00:15:4d:c4:c5:0d 431 | 10.0.171.170, 00:15:4d:ab:aa:e7 432 | 10.0.59.69, 00:15:4d:3b:45:64 433 | 10.0.52.141, 00:15:4d:34:8d:7b 434 | 10.0.129.164, 00:15:4d:81:a4:98 435 | 10.0.0.98, 00:15:4d:00:62:0c 436 | 10.0.222.19, 00:15:4d:de:13:08 437 | 10.0.164.29, 00:15:4d:a4:1d:7b 438 | 10.0.86.26, 00:15:4d:56:1a:11 439 | 10.0.127.171, 00:15:4d:7f:ab:bb 440 | 10.0.114.10, 00:15:4d:72:0a:85 441 | 10.0.55.123, 00:15:4d:37:7b:f3 442 | 10.0.89.92, 00:15:4d:59:5c:d6 443 | 10.0.31.168, 00:15:4d:1f:a8:be 444 | 10.0.138.99, 00:15:4d:8a:63:91 445 | 10.0.4.32, 00:15:4d:04:20:81 446 | 10.0.149.72, 00:15:4d:95:48:2f 447 | 10.0.213.222, 00:15:4d:d5:de:95 448 | 10.0.30.251, 00:15:4d:1e:fb:23 449 | 10.0.60.103, 00:15:4d:3c:67:11 450 | 10.0.137.88, 00:15:4d:89:58:2d 451 | 10.0.86.16, 00:15:4d:56:10:15 452 | 10.0.164.119, 00:15:4d:a4:77:07 453 | 10.0.44.89, 00:15:4d:2c:59:1a 454 | 10.0.149.205, 00:15:4d:95:cd:61 455 | 10.0.148.1, 00:15:4d:94:01:47 456 | 10.0.147.115, 00:15:4d:93:73:9a 457 | 10.0.254.89, 00:15:4d:fe:59:3c 458 | 10.0.165.84, 00:15:4d:a5:54:4b 459 | 10.0.238.19, 00:15:4d:ee:13:a2 460 | 10.0.148.122, 00:15:4d:94:7a:b7 461 | 10.0.9.51, 00:15:4d:09:33:55 462 | 10.0.2.202, 00:15:4d:02:ca:eb 463 | 10.0.253.117, 00:15:4d:fd:75:72 464 | 10.0.55.186, 00:15:4d:37:ba:77 465 | 10.0.166.31, 00:15:4d:a6:1f:9d 466 | 10.0.89.164, 00:15:4d:59:a4:07 467 | 10.0.117.157, 00:15:4d:75:9d:23 468 | 10.0.87.226, 00:15:4d:57:e2:21 469 | 10.0.56.68, 00:15:4d:38:44:5e 470 | 10.0.153.26, 00:15:4d:99:1a:d3 471 | 10.0.39.103, 00:15:4d:27:67:15 472 | 10.0.124.144, 00:15:4d:7c:90:f5 473 | 10.0.96.17, 00:15:4d:60:11:c5 474 | 10.0.195.128, 00:15:4d:c3:80:ae 475 | 10.0.104.150, 00:15:4d:68:96:7e 476 | 10.0.156.200, 00:15:4d:9c:c8:96 477 | 10.0.204.190, 00:15:4d:cc:be:1f 478 | 10.0.86.105, 00:15:4d:56:69:0f 479 | 10.0.213.5, 00:15:4d:d5:05:45 480 | 10.0.62.172, 00:15:4d:3e:ac:77 481 | 10.0.129.232, 00:15:4d:81:e8:7a 482 | 10.0.176.5, 00:15:4d:b0:05:48 483 | 10.0.190.93, 00:15:4d:be:5d:60 484 | 10.0.19.112, 00:15:4d:13:70:bd 485 | 10.0.184.232, 00:15:4d:b8:e8:26 486 | 10.0.98.248, 00:15:4d:62:f8:e2 487 | 10.0.69.84, 00:15:4d:45:54:e2 488 | 10.0.92.106, 00:15:4d:5c:6a:d7 489 | 10.0.47.188, 00:15:4d:2f:bc:54 490 | 10.0.218.82, 00:15:4d:da:52:57 491 | 10.0.132.60, 00:15:4d:84:3c:c8 492 | 10.0.71.181, 00:15:4d:47:b5:b6 493 | 10.0.187.5, 00:15:4d:bb:05:fa 494 | 10.0.194.25, 00:15:4d:c2:19:7c 495 | 10.0.92.6, 00:15:4d:5c:06:ea 496 | 10.0.198.249, 00:15:4d:c6:f9:57 497 | 10.0.187.141, 00:15:4d:bb:8d:58 498 | 10.0.180.111, 00:15:4d:b4:6f:e5 499 | 10.0.23.1, 00:15:4d:17:01:9f 500 | 10.0.84.243, 00:15:4d:54:f3:3f 501 | 10.0.241.172, 00:15:4d:f1:ac:6b 502 | 10.0.227.128, 00:15:4d:e3:80:0b 503 | 10.0.110.106, 00:15:4d:6e:6a:7f 504 | 10.0.95.143, 00:15:4d:5f:8f:85 505 | 10.0.46.63, 00:15:4d:2e:3f:59 506 | 10.0.176.140, 00:15:4d:b0:8c:7d 507 | 10.0.195.155, 00:15:4d:c3:9b:6b 508 | 10.0.214.76, 00:15:4d:d6:4c:93 509 | 10.0.6.174, 00:15:4d:06:ae:5a 510 | 10.0.58.186, 00:15:4d:3a:ba:88 511 | 10.0.169.249, 00:15:4d:a9:f9:e6 512 | 10.0.187.211, 00:15:4d:bb:d3:2c 513 | -------------------------------------------------------------------------------- /l4lb/l4lb_map.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 3 | # Copyright (c) 2018 Netronome Systems, Inc. 4 | 5 | import argparse 6 | import csv 7 | import json 8 | import os 9 | import subprocess 10 | from bpftool_utils import * 11 | 12 | parser = argparse.ArgumentParser(description="Initialize load balancer map") 13 | parser.add_argument('-i', '--interface', action='store', required=True, 14 | help='xdp network interface') 15 | parser.add_argument('-f', '--file', action='store', required=True, 16 | help='Input file containing destination data') 17 | parser.add_argument('-s', '--saddr', action='store', required=False, type=str, 18 | default='10.0.0.1', help='source ip for outgoing packets') 19 | args = parser.parse_args() 20 | 21 | tmpfile = 'tmp_bpftool.txt' # batch map updates into a file for bpftool 22 | stats_zero = '00 00 00 00 00 00 00 00' # initialize stats to (u64) zero 23 | 24 | interface = args.interface 25 | 26 | try: 27 | map_id = str(get_map_ids(interface)[0]) 28 | max_dest = get_map_entries(map_id) # map size as defined by xdp program 29 | except: 30 | print("Error finding map for dev: %s" % interface) 31 | sys.exit(1) 32 | 33 | try: 34 | dest_file = open(args.file, 'r') 35 | dest_hosts = list(csv.reader(dest_file)) 36 | dest_count = len(dest_hosts) 37 | except: 38 | print("Error reading file") 39 | sys.exit(1) 40 | 41 | if dest_count > max_dest: 42 | print("Warning: only the first %d destinations will be used" % max_dest) 43 | else: 44 | print("Loading file with %d destinations" % dest_count) 45 | 46 | batchfile = open(tmpfile, 'w') 47 | 48 | # iterate through data in input file, if it contains less values than max_dest 49 | # map will be filled as round robin 50 | for key in range (0, max_dest): 51 | target_id = key % dest_count 52 | 53 | # bpftool requires data as individual bytes 54 | keyval1 = str(key & 0xFF) 55 | keyval2 = str(key >> 8) 56 | 57 | saddr = args.saddr.split('.') # source IP for egress packets 58 | daddr = dest_hosts[target_id][0].split('.') # IP of the target server 59 | 60 | dmac_hex = dest_hosts[target_id][1].split(':') # MAC of the target server 61 | dmac = [str(int(byte, 16)) for byte in dmac_hex] # convert hex to integers 62 | 63 | # Fill in map using struct iptnl_info arrangement as specified in l4lb_xdp.c 64 | COMMAND = (['map update id', map_id, 65 | 'key', keyval1, keyval2, '00 00', 66 | 'value', saddr[0], saddr[1], saddr[2], saddr[3], 67 | daddr[0], daddr[1], daddr[2], daddr[3], 68 | stats_zero, stats_zero, 69 | dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5], 70 | '00 00 \n']) 71 | COMMAND = ' '.join(COMMAND) 72 | batchfile.write(COMMAND) 73 | 74 | batchfile.close() 75 | subprocess.check_output('bpftool batch file %s' % tmpfile, shell=True) 76 | -------------------------------------------------------------------------------- /l4lb/l4lb_stats.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 3 | # Copyright (c) 2018 Netronome Systems, Inc. 4 | 5 | import argparse 6 | import json 7 | import os 8 | import subprocess 9 | import sys 10 | import time 11 | from bpftool_utils import * 12 | 13 | parser = argparse.ArgumentParser(description="Display load balancer statistics") 14 | parser.add_argument('-i', '--interface', action='store', required=True, 15 | help='xdp network interface') 16 | args = parser.parse_args() 17 | interface = args.interface 18 | 19 | prev = {} 20 | 21 | while True: 22 | n = 1 23 | pkt_tot = 0 24 | bit_tot = 0 25 | values = {} 26 | clock = time.time() 27 | 28 | # obtain map values 29 | try: 30 | map_id = get_map_ids(interface)[0] 31 | map_vals = dump_map(map_id) 32 | xdp_type = get_map_dev(map_id) 33 | except: 34 | print("Error accessing eBPF map") 35 | time.sleep(1) 36 | continue 37 | 38 | # get totals for each destination ip 39 | for record in map_vals: 40 | # obtain values from map from positions defined by struct iptnl_info 41 | dest_ip = [int(byte, 16) for byte in record['value'][4:8]] 42 | bw = hex_list_to_int(record['value'][8:16]) 43 | pkt = hex_list_to_int(record['value'][16:24]) 44 | 45 | ip = '%s.%s.%s.%s' % (dest_ip[0], dest_ip[1], dest_ip[2], dest_ip[3]) 46 | 47 | if ip in values: 48 | values[ip][0] += pkt 49 | values[ip][1] += bw 50 | else: 51 | values[ip] = [pkt, bw] 52 | 53 | os.system("clear") 54 | pr = ("== Load balancer outbound statistics [%s] ==\n\n" % xdp_type) 55 | 56 | # Calculate network rate using diff from previous sample 57 | for key in sorted(values): 58 | bitrate = 0 59 | pktrate = 0 60 | 61 | if key in prev: 62 | sample_period = clock - prev[key][2] 63 | pktrate = int((values[key][0] - prev[key][0]) / sample_period) 64 | bitrate = int((values[key][1] - prev[key][1]) / sample_period) * 8 65 | 66 | prev[key] = [values[key][0], values[key][1], clock] 67 | 68 | if pktrate >= 0: # on map refill stats are reset causes neg stats 69 | pr += ("{:4d}\t{:15s}\t{:12,} pkts/s\t{:15,} bits/s\n" 70 | .format(n, key, pktrate, bitrate)) 71 | pkt_tot += pktrate 72 | bit_tot += bitrate 73 | n += 1 74 | 75 | pr += "\n[Totals]\t\t{:12,} pkts/s\t{:15,} bits/s".format(pkt_tot, bit_tot) 76 | print(pr) 77 | 78 | time.sleep(max(0, 1 - (time.time() - clock))) 79 | -------------------------------------------------------------------------------- /l4lb/l4lb_xdp.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | // Copyright (c) 2018 Netronome Systems, Inc. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "bpf_endian.h" 16 | #include "bpf_helpers.h" 17 | #include "jhash.h" 18 | 19 | #define MAX_SERVERS 512 20 | /* 0x3FFF mask to check for fragment offset field */ 21 | #define IP_FRAGMENTED 65343 22 | 23 | struct pkt_meta { 24 | __be32 src; 25 | __be32 dst; 26 | union { 27 | __u32 ports; 28 | __u16 port16[2]; 29 | }; 30 | }; 31 | 32 | struct dest_info { 33 | __u32 saddr; 34 | __u32 daddr; 35 | __u64 bytes; 36 | __u64 pkts; 37 | __u8 dmac[6]; 38 | }; 39 | 40 | struct bpf_map_def SEC("maps") servers = { 41 | .type = BPF_MAP_TYPE_HASH, 42 | .key_size = sizeof(__u32), 43 | .value_size = sizeof(struct dest_info), 44 | .max_entries = MAX_SERVERS, 45 | }; 46 | 47 | static __always_inline struct dest_info *hash_get_dest(struct pkt_meta *pkt) 48 | { 49 | __u32 key; 50 | struct dest_info *tnl; 51 | 52 | /* hash packet source ip with both ports to obtain a destination */ 53 | key = jhash_2words(pkt->src, pkt->ports, MAX_SERVERS) % MAX_SERVERS; 54 | 55 | /* get destination's network details from map */ 56 | tnl = bpf_map_lookup_elem(&servers, &key); 57 | if (!tnl) { 58 | /* if entry does not exist, fallback to key 0 */ 59 | key = 0; 60 | tnl = bpf_map_lookup_elem(&servers, &key); 61 | } 62 | return tnl; 63 | } 64 | 65 | static __always_inline bool parse_udp(void *data, __u64 off, void *data_end, 66 | struct pkt_meta *pkt) 67 | { 68 | struct udphdr *udp; 69 | 70 | udp = data + off; 71 | if (udp + 1 > data_end) 72 | return false; 73 | 74 | pkt->port16[0] = udp->source; 75 | pkt->port16[1] = udp->dest; 76 | 77 | return true; 78 | } 79 | 80 | static __always_inline bool parse_tcp(void *data, __u64 off, void *data_end, 81 | struct pkt_meta *pkt) 82 | { 83 | struct tcphdr *tcp; 84 | 85 | tcp = data + off; 86 | if (tcp + 1 > data_end) 87 | return false; 88 | 89 | pkt->port16[0] = tcp->source; 90 | pkt->port16[1] = tcp->dest; 91 | 92 | return true; 93 | } 94 | 95 | static __always_inline void set_ethhdr(struct ethhdr *new_eth, 96 | const struct ethhdr *old_eth, 97 | const struct dest_info *tnl, 98 | __be16 h_proto) 99 | { 100 | memcpy(new_eth->h_source, old_eth->h_dest, sizeof(new_eth->h_source)); 101 | memcpy(new_eth->h_dest, tnl->dmac, sizeof(new_eth->h_dest)); 102 | new_eth->h_proto = h_proto; 103 | } 104 | 105 | static __always_inline int process_packet(struct xdp_md *ctx, __u64 off) 106 | { 107 | void *data_end = (void *)(long)ctx->data_end; 108 | void *data = (void *)(long)ctx->data; 109 | struct pkt_meta pkt = {}; 110 | struct ethhdr *new_eth; 111 | struct ethhdr *old_eth; 112 | struct dest_info *tnl; 113 | struct iphdr iph_tnl; 114 | struct iphdr *iph; 115 | __u16 *next_iph_u16; 116 | __u16 pkt_size; 117 | __u16 payload_len; 118 | __u8 protocol; 119 | u32 csum = 0; 120 | 121 | iph = data + off; 122 | if (iph + 1 > data_end) 123 | return XDP_DROP; 124 | if (iph->ihl != 5) 125 | return XDP_DROP; 126 | 127 | protocol = iph->protocol; 128 | payload_len = bpf_ntohs(iph->tot_len); 129 | off += sizeof(struct iphdr); 130 | 131 | /* do not support fragmented packets as L4 headers may be missing */ 132 | if (iph->frag_off & IP_FRAGMENTED) 133 | return XDP_DROP; 134 | 135 | pkt.src = iph->saddr; 136 | pkt.dst = iph->daddr; 137 | 138 | /* obtain port numbers for UDP and TCP traffic */ 139 | if (protocol == IPPROTO_TCP) { 140 | if (!parse_tcp(data, off, data_end, &pkt)) 141 | return XDP_DROP; 142 | } else if (protocol == IPPROTO_UDP) { 143 | if (!parse_udp(data, off, data_end, &pkt)) 144 | return XDP_DROP; 145 | } else { 146 | return XDP_PASS; 147 | } 148 | 149 | /* allocate a destination using packet hash and map lookup */ 150 | tnl = hash_get_dest(&pkt); 151 | if (!tnl) 152 | return XDP_DROP; 153 | 154 | /* extend the packet for ip header encapsulation */ 155 | if (bpf_xdp_adjust_head(ctx, 0 - (int)sizeof(struct iphdr))) 156 | return XDP_DROP; 157 | 158 | data = (void *)(long)ctx->data; 159 | data_end = (void *)(long)ctx->data_end; 160 | 161 | /* relocate ethernet header to start of packet and set MACs */ 162 | new_eth = data; 163 | old_eth = data + sizeof(*iph); 164 | 165 | if (new_eth + 1 > data_end || old_eth + 1 > data_end || 166 | iph + 1 > data_end) 167 | return XDP_DROP; 168 | 169 | set_ethhdr(new_eth, old_eth, tnl, bpf_htons(ETH_P_IP)); 170 | 171 | /* create an additional ip header for encapsulation */ 172 | iph_tnl.version = 4; 173 | iph_tnl.ihl = sizeof(*iph) >> 2; 174 | iph_tnl.frag_off = 0; 175 | iph_tnl.protocol = IPPROTO_IPIP; 176 | iph_tnl.check = 0; 177 | iph_tnl.id = 0; 178 | iph_tnl.tos = 0; 179 | iph_tnl.tot_len = bpf_htons(payload_len + sizeof(*iph)); 180 | iph_tnl.daddr = tnl->daddr; 181 | iph_tnl.saddr = tnl->saddr; 182 | iph_tnl.ttl = 8; 183 | 184 | /* calculate ip header checksum */ 185 | next_iph_u16 = (__u16 *)&iph_tnl; 186 | #pragma clang loop unroll(full) 187 | for (int i = 0; i < (int)sizeof(*iph) >> 1; i++) 188 | csum += *next_iph_u16++; 189 | iph_tnl.check = ~((csum & 0xffff) + (csum >> 16)); 190 | 191 | iph = data + sizeof(*new_eth); 192 | *iph = iph_tnl; 193 | 194 | /* increment map counters */ 195 | pkt_size = (__u16)(data_end - data); /* payload size excl L2 crc */ 196 | __sync_fetch_and_add(&tnl->pkts, 1); 197 | __sync_fetch_and_add(&tnl->bytes, pkt_size); 198 | 199 | return XDP_TX; 200 | } 201 | 202 | SEC("xdp") 203 | int loadbal(struct xdp_md *ctx) 204 | { 205 | void *data_end = (void *)(long)ctx->data_end; 206 | void *data = (void *)(long)ctx->data; 207 | struct ethhdr *eth = data; 208 | __u32 eth_proto; 209 | __u32 nh_off; 210 | 211 | nh_off = sizeof(struct ethhdr); 212 | if (data + nh_off > data_end) 213 | return XDP_DROP; 214 | eth_proto = eth->h_proto; 215 | 216 | /* demo program only accepts ipv4 packets */ 217 | if (eth_proto == bpf_htons(ETH_P_IP)) 218 | return process_packet(ctx, nh_off); 219 | else 220 | return XDP_PASS; 221 | } 222 | -------------------------------------------------------------------------------- /programmable_rss/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | 3 | TARGET := rss 4 | 5 | LLC ?= llc 6 | CLANG ?= clang 7 | CC ?= gcc 8 | 9 | LIBBPF_DIR = ../libbpf/src/ 10 | 11 | XDP_C = ${TARGET:=_kern.c} 12 | XDP_OBJ = ${XDP_C:.c=.o} 13 | USER_C = ${TARGET:=_user.c} 14 | USER_OBJ = ${USER_C:.c=.o} 15 | OBJECT_LIBBPF = $(LIBBPF_DIR)/libbpf.a 16 | 17 | CFLAGS ?= -I$(LIBBPF_DIR)/root/usr/include/ 18 | CFLAGS += -I../headers/ 19 | LDFLAGS ?= -L$(LIBBPF_DIR) 20 | 21 | LIBS = -lbpf -lelf 22 | 23 | all: llvm-check $(TARGET) $(XDP_OBJ) 24 | 25 | .PHONY: clean $(CLANG) $(LLC) 26 | 27 | clean: 28 | cd $(LIBBPF_DIR) && $(MAKE) clean; 29 | rm -f $(TARGET) 30 | rm -f $(XDP_OBJ) 31 | rm -f $(USER_OBJ) 32 | rm -f *.ll 33 | 34 | llvm-check: $(CLANG) $(LLC) 35 | @for TOOL in $^ ; do \ 36 | if [ ! $$(command -v $${TOOL} 2>/dev/null) ]; then \ 37 | echo "*** ERROR: Cannot find tool $${TOOL}" ;\ 38 | exit 1; \ 39 | else true; fi; \ 40 | done 41 | 42 | $(OBJECT_LIBBPF): 43 | @if [ ! -d $(LIBBPF_DIR) ]; then \ 44 | echo "Error: Need libbpf submodule"; \ 45 | echo "May need to run git submodule update --init"; \ 46 | exit 1; \ 47 | else \ 48 | cd $(LIBBPF_DIR) && $(MAKE) all; \ 49 | mkdir -p root; DESTDIR=root $(MAKE) install_headers; \ 50 | fi 51 | 52 | $(TARGET): %: %_user.c $(OBJECT_LIBBPF) Makefile 53 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) 54 | 55 | $(XDP_OBJ): %.o: %.c 56 | $(CLANG) -S \ 57 | -D __BPF_TRACING__ \ 58 | $(CFLAGS) \ 59 | -Wall \ 60 | -Wno-unused-value -Wno-pointer-sign \ 61 | -Wno-compare-distinct-pointer-types \ 62 | -Werror \ 63 | -O2 -emit-llvm -c -g $< 64 | $(LLC) -march=bpf -filetype=obj -o $@ ${@:.o=.ll} 65 | -------------------------------------------------------------------------------- /programmable_rss/README.rst: -------------------------------------------------------------------------------- 1 | Programmable RSS Demo 2 | ===================== 3 | 4 | Overview of RSS 5 | ~~~~~~~~~~~~~~~ 6 | 7 | Receive Side Scaling (RSS) is utilised in modern network cards to distribute 8 | network traffic between the host CPUs through the use of multiple queues [1]_. 9 | A hash function is applied to the packet headers (commonly the 4 tuple) to 10 | generate a hash for the flow. This hash value is subsequently used as the index 11 | to an indirection table which designates the destination RSS queue. 12 | 13 | Symmetric RSS is a RSS implementation where packets in both direction of a flow 14 | map to the same queue, i.e. for a connection between hosts A and B, both packets 15 | sent by A and by B will be placed on the same queue. 16 | This is useful for IDS/Firewalls monitoring traffic flows, by ensuring CPU state 17 | access locality across all packets of the flow one can minimise cache bouncing 18 | and achieve higher performance. 19 | 20 | Custom header RSS (or Encapsulated RSS) allows users to benefit from RSS even if 21 | they are using custom headers or uncommon encapsulations. Default RSS 22 | implementations are only able to parse common protocols. With programmable RSS 23 | users can include any field of the headers in RSS calculation. Users can also 24 | parse any encapsulation protocol they have in their networks. This is beneficial 25 | to overlay and trunk networks, where the outer IP header is relatively static 26 | resulting in a badly distributed RSS. The inner IP header addresses can have 27 | more variance hence a better RSS distribution. 28 | 29 | The RSS algorithms available on network cards are commonly closed source or 30 | fixed in hardware. In Linux kernel 4.18, the capability of programming the 31 | RX RSS through eBPF was introduced. 32 | 33 | Demo App 34 | ~~~~~~~~ 35 | 36 | This program will demonstrate how XDP offload can be utilised to provide user 37 | programmable RSS. As this is a demo, it showcases multiple RSS capabilities, 38 | however a deployment would likely only implement one of these RSS options. 39 | 40 | The demo allows for incoming packets to be distributed to 41 | 42 | - a single queue, chosen by the user through a userspace utility 43 | - distributed queues using a hash algorithm 44 | - distributed queues using a Symmetric RSS hash algorithm 45 | - distributed queues using a hash algorithm against the IPinIP inner headers 46 | 47 | This demo shows support for simple IPinIP encapsulation because it's easy to set 48 | up and test, but UDP encapsulations (VXLAN, Geneve, FOU, GUE, etc.), NSH, QUIC 49 | or any other protocol can easily be implemented. 50 | 51 | Minimum Requirements for Demo 52 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 53 | 54 | This program requires a XDP offload compatible SmartNIC. It cannot be run in 55 | driver mode. 56 | 57 | - Linux kernel 4.18 58 | - clang / LLVM 4.0 59 | - libelf-dev (Ubuntu) / elfutils-devel (Fedora) 60 | - Agilio® eBPF firmware for HW offload - July 2018 61 | (available from `Netronome's support website`_) 62 | 63 | .. _Netronome's support website: https://help.netronome.com/ 64 | 65 | Loading the Demo 66 | ~~~~~~~~~~~~~~~~ 67 | 68 | The program is compiled using an included libbpf. To compile the user space and 69 | XDP programs :: 70 | 71 | $ make 72 | 73 | To load the program :: 74 | 75 | # ./rss -i INTERFACE 76 | 77 | Traffic Generation 78 | ~~~~~~~~~~~~~~~~~~ 79 | 80 | Traffic can be generated using a variety of tools, but for ease of use a pcap 81 | file has been supplied (traffic_IPIP.pcap). This traffic can be replayed 82 | using the following instructions. 83 | 84 | For the host running the eBPF program, ensure promiscuous mode is enabled to 85 | allow for all packets to be received. This is required as the destination MAC 86 | address set within the pcap file has been set for another host :: 87 | 88 | # ip link set dev ens4np0 promisc on 89 | 90 | On the traffic generator, use tcpreplay to retransmit the test traffic :: 91 | 92 | # tcpreplay -i ens0 -l 500 traffic_IPIP.pcap 93 | 94 | Examples 95 | ~~~~~~~~ 96 | 97 | The following examples will utilise the interface ens4np0 which has 8 queues 98 | set within ethtool. All examples are run against the same IPinIP traffic :: 99 | 100 | # ethtool -L ens4np0 combined 8 rx 0 tx 0 101 | 102 | Sending all traffic to queue 5 :: 103 | 104 | # ./rss -i ens4np0 -q 5 105 | ------------------------------------------------- 106 | RSS Queue 0: 0 107 | RSS Queue 1: 0 108 | RSS Queue 2: 0 109 | RSS Queue 3: 0 110 | RSS Queue 4: 0 111 | RSS Queue 5: 804,081 112 | RSS Queue 6: 0 113 | RSS Queue 7: 0 114 | 115 | Distributing traffic using jhash algorithm :: 116 | 117 | # ./rss -i ens4np0 -j 118 | ------------------------------------------------- 119 | RSS Queue 0: 0 120 | RSS Queue 1: 0 121 | RSS Queue 2: 0 122 | RSS Queue 3: 0 123 | RSS Queue 4: 0 124 | RSS Queue 5: 402,400 125 | RSS Queue 6: 402,400 126 | RSS Queue 7: 0 127 | 128 | Distributing traffic using jhash algorithm with Symmetric RSS :: 129 | 130 | # ./rss -i ens4np0 -j -s 131 | ------------------------------------------------- 132 | RSS Queue 0: 0 133 | RSS Queue 1: 0 134 | RSS Queue 2: 0 135 | RSS Queue 3: 0 136 | RSS Queue 4: 0 137 | RSS Queue 5: 0 138 | RSS Queue 6: 804,797 139 | RSS Queue 7: 0 140 | 141 | Distributing traffic using jhash algorithm with encapsulated IPs :: 142 | 143 | # ./rss -i ens4np0 -j -e 144 | ------------------------------------------------- 145 | RSS Queue 0: 72,449 146 | RSS Queue 1: 104,648 147 | RSS Queue 2: 120,747 148 | RSS Queue 3: 128,797 149 | RSS Queue 4: 64,398 150 | RSS Queue 5: 128,792 151 | RSS Queue 6: 72,447 152 | RSS Queue 7: 112,693 153 | 154 | Distributing traffic using jhash algorithm with encapsulated IPs on 4 queues :: 155 | 156 | # ./rss -i ens4np0 -j -e -m 4 157 | ------------------------------------------------- 158 | RSS Queue 0: 136,820 159 | RSS Queue 1: 233,403 160 | RSS Queue 2: 193,158 161 | RSS Queue 3: 241,450 162 | 163 | Removing the Demo 164 | ~~~~~~~~~~~~~~~~~ 165 | 166 | The XDP program will automatically be unloaded on exiting the rss program 167 | 168 | .. [1] https://www.kernel.org/doc/Documentation/networking/scaling.txt 169 | -------------------------------------------------------------------------------- /programmable_rss/rss_common.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | // Copyright (c) 2018 Netronome Systems, Inc. 3 | 4 | #define MAX_RSS_QUEUES 64 5 | 6 | enum { 7 | QUEUE_STATIC = 0, 8 | QUEUE_HASH, 9 | QUEUE_SYMMETRIC, 10 | QUEUE_ENCAP, 11 | }; 12 | 13 | struct queue_select_ctrl { 14 | __u8 select_mode; 15 | __u8 queue_static; 16 | }; 17 | 18 | struct indirect_queue { 19 | __u32 packet_cnt; 20 | __u8 queue_num; 21 | }; 22 | -------------------------------------------------------------------------------- /programmable_rss/rss_kern.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | // Copyright (c) 2018 Netronome Systems, Inc. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "bpf_endian.h" 15 | #include "bpf_helpers.h" 16 | #include "jhash.h" 17 | #include "rss_common.h" 18 | 19 | struct pkt_meta { 20 | __be32 src; 21 | __be32 dst; 22 | __be32 srcv6[4]; 23 | __be32 dstv6[4]; 24 | union { 25 | __u32 ports; 26 | __u16 port16[2]; 27 | }; 28 | __u8 protocol; 29 | }; 30 | 31 | struct bpf_map_def SEC("maps") ctrl_map = { 32 | .type = BPF_MAP_TYPE_ARRAY, 33 | .key_size = sizeof(__u32), 34 | .value_size = sizeof(struct queue_select_ctrl), 35 | .max_entries = 1, 36 | }; 37 | 38 | struct bpf_map_def SEC("maps") indirect_map = { 39 | .type = BPF_MAP_TYPE_ARRAY, 40 | .key_size = sizeof(__u32), 41 | .value_size = sizeof(struct indirect_queue), 42 | .max_entries = MAX_RSS_QUEUES, 43 | }; 44 | 45 | static __always_inline __u32 hash_tuples(struct pkt_meta *pkt, bool is_ip6) 46 | { 47 | __u32 a; 48 | __u32 b; 49 | 50 | /* hash packet ip and ports to obtain a key for rss indirection tbl */ 51 | if (is_ip6) { 52 | a = jhash2(pkt->srcv6, 4, 0xc55); 53 | b = jhash2(pkt->dstv6, 4, 0x1234); 54 | return jhash_3words(a, b, pkt->ports, 0xeb0f); 55 | } else { 56 | return jhash_3words(pkt->src, pkt->dst, pkt->ports, 0xeb0f); 57 | } 58 | } 59 | 60 | static __always_inline bool parse_udp(void *data, __u64 off, void *data_end, 61 | struct pkt_meta *pkt) 62 | { 63 | struct udphdr *udp; 64 | 65 | udp = data + off; 66 | if (udp + 1 > data_end) 67 | return false; 68 | 69 | pkt->port16[0] = udp->source; 70 | pkt->port16[1] = udp->dest; 71 | 72 | return true; 73 | } 74 | 75 | static __always_inline bool parse_tcp(void *data, __u64 off, void *data_end, 76 | struct pkt_meta *pkt) 77 | { 78 | struct tcphdr *tcp; 79 | 80 | tcp = data + off; 81 | if (tcp + 1 > data_end) 82 | return false; 83 | 84 | pkt->port16[0] = tcp->source; 85 | pkt->port16[1] = tcp->dest; 86 | 87 | return true; 88 | } 89 | 90 | static __always_inline bool parse_ip4(void *data, __u64 off, void *data_end, 91 | struct pkt_meta *pkt) 92 | { 93 | struct iphdr *iph; 94 | 95 | iph = data + off; 96 | if (iph + 1 > data_end) 97 | return false; 98 | 99 | if (iph->ihl != 5) 100 | return false; 101 | 102 | pkt->src = iph->saddr; 103 | pkt->dst = iph->daddr; 104 | pkt->protocol = iph->protocol; 105 | 106 | return true; 107 | } 108 | 109 | static __always_inline bool parse_ip6(void *data, __u64 off, void *data_end, 110 | struct pkt_meta *pkt) 111 | { 112 | struct ipv6hdr *ip6h; 113 | 114 | ip6h = data + off; 115 | if (ip6h + 1 > data_end) 116 | return false; 117 | 118 | memcpy(pkt->srcv6, ip6h->saddr.s6_addr32, 16); 119 | memcpy(pkt->dstv6, ip6h->daddr.s6_addr32, 16); 120 | pkt->protocol = ip6h->nexthdr; 121 | 122 | return true; 123 | } 124 | 125 | static __always_inline void sort_tuple(struct pkt_meta *pkt, bool is_ip6) 126 | { 127 | __be32 temp_ipv6[4]; 128 | __be32 temp_ip; 129 | __u16 temp_port; 130 | __u64 tot_dst; 131 | __u64 tot_src; 132 | 133 | /* sort tuple to ensure consistency for both flow directions */ 134 | if (is_ip6) { 135 | tot_src = pkt->srcv6[0] + pkt->srcv6[1] 136 | + pkt->srcv6[2] + pkt->srcv6[3]; 137 | tot_dst = pkt->dstv6[0] + pkt->dstv6[1] 138 | + pkt->dstv6[2] + pkt->dstv6[3]; 139 | 140 | if (tot_src < tot_dst) { 141 | memcpy(temp_ipv6, pkt->srcv6, 16); 142 | memcpy(pkt->srcv6, pkt->dstv6, 16); 143 | memcpy(pkt->dstv6, temp_ipv6, 16); 144 | } 145 | } else { 146 | if (pkt->src < pkt->dst) { 147 | temp_ip = pkt->src; 148 | pkt->src = pkt->dst; 149 | pkt->dst = temp_ip; 150 | } 151 | } 152 | 153 | if (pkt->port16[0] < pkt->port16[1]) { 154 | temp_port = pkt->port16[0]; 155 | pkt->port16[0] = pkt->port16[1]; 156 | pkt->port16[1] = temp_port; 157 | } 158 | } 159 | 160 | SEC("xdp") 161 | int process_packet(struct xdp_md *ctx) 162 | { 163 | void *data_end = (void *)(long)ctx->data_end; 164 | void *data = (void *)(long)ctx->data; 165 | struct queue_select_ctrl *queue_ctrl; 166 | struct indirect_queue *dest_q; 167 | struct ethhdr *eth = data; 168 | struct pkt_meta pkt = {}; 169 | bool symmetric = false; 170 | bool use_encap = false; 171 | bool is_ip6 = false; 172 | bool jhash = false; 173 | __u32 eth_proto; 174 | __u32 hash; 175 | __u32 key; 176 | __u32 off; 177 | 178 | /* determine hashing mode using map lookup */ 179 | key = 0; 180 | 181 | queue_ctrl = bpf_map_lookup_elem(&ctrl_map, &key); 182 | if (!queue_ctrl) 183 | return XDP_PASS; 184 | 185 | switch (queue_ctrl->select_mode) { 186 | case QUEUE_STATIC: 187 | jhash = false; 188 | key = queue_ctrl->queue_static; 189 | break; 190 | case QUEUE_HASH: 191 | jhash = true; 192 | break; 193 | case QUEUE_SYMMETRIC: 194 | jhash = true; 195 | symmetric = true; 196 | break; 197 | case QUEUE_ENCAP: 198 | jhash = true; 199 | use_encap = true; 200 | break; 201 | default: 202 | return XDP_PASS; 203 | } 204 | 205 | /* parse packet for IP Addresses and Ports */ 206 | off = sizeof(struct ethhdr); 207 | if (data + off > data_end) 208 | return XDP_PASS; 209 | 210 | eth_proto = eth->h_proto; 211 | 212 | if (eth_proto == bpf_htons(ETH_P_IP)) { 213 | if (!parse_ip4(data, off, data_end, &pkt)) 214 | return XDP_PASS; 215 | off += sizeof(struct iphdr); 216 | } else if (eth_proto == bpf_htons(ETH_P_IPV6)) { 217 | if (!parse_ip6(data, off, data_end, &pkt)) 218 | return XDP_PASS; 219 | is_ip6 = true; 220 | off += sizeof(struct ipv6hdr); 221 | } else { 222 | return XDP_PASS; 223 | } 224 | 225 | /* if IPinIP packet allow for second IP header */ 226 | if (pkt.protocol == IPPROTO_IPIP) { 227 | if (use_encap) { 228 | if (!parse_ip4(data, off, data_end, &pkt)) 229 | return XDP_PASS; 230 | is_ip6 = false; 231 | } 232 | off += sizeof(struct iphdr); 233 | } else if (pkt.protocol == IPPROTO_IPV6) { 234 | if (use_encap) { 235 | if (!parse_ip6(data, off, data_end, &pkt)) 236 | return XDP_PASS; 237 | is_ip6 = true; 238 | } 239 | off += sizeof(struct ipv6hdr); 240 | } 241 | 242 | if (data + off > data_end) 243 | return XDP_PASS; 244 | 245 | /* obtain port numbers for UDP and TCP traffic */ 246 | if (pkt.protocol == IPPROTO_TCP) { 247 | if (!parse_tcp(data, off, data_end, &pkt)) 248 | return XDP_PASS; 249 | } else if (pkt.protocol == IPPROTO_UDP) { 250 | if (!parse_udp(data, off, data_end, &pkt)) 251 | return XDP_PASS; 252 | } else { 253 | pkt.ports = 0; 254 | } 255 | 256 | if (symmetric) 257 | sort_tuple(&pkt, is_ip6); 258 | 259 | if (jhash) { 260 | /* set map lookup key using 4 tuple hash */ 261 | hash = hash_tuples(&pkt, is_ip6); 262 | key = hash % MAX_RSS_QUEUES; 263 | } 264 | 265 | /* HW cannot perform modulus on varying values so use indirection tbl */ 266 | dest_q = bpf_map_lookup_elem(&indirect_map, &key); 267 | if (!dest_q) 268 | return XDP_PASS; 269 | 270 | ctx->rx_queue_index = dest_q->queue_num; 271 | /* increment queue packet counter */ 272 | __sync_fetch_and_add(&dest_q->packet_cnt, 1); 273 | 274 | return XDP_PASS; 275 | } 276 | -------------------------------------------------------------------------------- /programmable_rss/rss_user.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | // Copyright (c) 2018 Netronome Systems, Inc. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "rss_common.h" 20 | 21 | static int ifindex; 22 | static __u32 xdp_flags; 23 | 24 | static void unload_prog(int sig) 25 | { 26 | bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); 27 | printf("unloading xdp program...\n"); 28 | exit(0); 29 | } 30 | 31 | static int get_interface_rx_channels(int ifindex) 32 | { 33 | struct ethtool_channels cmd; 34 | struct ifreq req; 35 | int socketfd; 36 | 37 | socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 38 | if (socketfd == -1) 39 | return -1; 40 | 41 | /* get interface name */ 42 | req.ifr_ifindex = ifindex; 43 | if (ioctl(socketfd, SIOCGIFNAME, &req) == -1) 44 | return -1; 45 | 46 | /* get ethtool channels */ 47 | req.ifr_data = (void *)&cmd; 48 | cmd.cmd = ETHTOOL_GCHANNELS; 49 | 50 | if (ioctl(socketfd, SIOCETHTOOL, &req) == -1) 51 | return -1; 52 | 53 | return cmd.combined_count + cmd.rx_count; 54 | } 55 | 56 | static int poll_stats(int indirect_map_fd, int queues_enabled, int poll_secs) 57 | { 58 | struct indirect_queue indirect_lookup; 59 | int values[queues_enabled]; 60 | int prev[queues_enabled]; 61 | struct timespec t1, t2; 62 | double time_taken; 63 | long queue_rate; 64 | int queue; 65 | int i; 66 | 67 | /* initialize arrays */ 68 | memset(prev, 0, sizeof(prev)); 69 | memset(values, 0, sizeof(prev)); 70 | /* use thousand separators in printf */ 71 | setlocale(LC_NUMERIC, "en_US"); 72 | 73 | clock_gettime(CLOCK_MONOTONIC_RAW, &t1); 74 | 75 | while (true) { 76 | printf("-------------------------------------------------\n\n"); 77 | for (i = 0; i < MAX_RSS_QUEUES; i++) { 78 | if (bpf_map_lookup_elem(indirect_map_fd, &i, 79 | &indirect_lookup) != 0) { 80 | printf("Err lookup failed\n"); 81 | return 0; 82 | } 83 | queue = indirect_lookup.queue_num; 84 | values[queue] += indirect_lookup.packet_cnt; 85 | } 86 | 87 | clock_gettime(CLOCK_MONOTONIC_RAW, &t2); 88 | /* calc sample period to allow rate to be obtained */ 89 | time_taken = (t2.tv_sec + 1.0e-9 * t2.tv_nsec) - 90 | (t1.tv_sec + 1.0e-9 * t1.tv_nsec); 91 | 92 | for (i = 0; i < queues_enabled; i++) { 93 | queue_rate = (values[i] - prev[i]) / time_taken; 94 | printf("RSS Queue %d: %'ld\n", i, queue_rate); 95 | prev[i] = values[i]; 96 | values[i] = 0; 97 | } 98 | t1 = t2; 99 | usleep(poll_secs * 1000 * 1000); 100 | } 101 | } 102 | 103 | static void usage(const char *prog) 104 | { 105 | fprintf(stderr, 106 | "%s -i interface [OPTS]\n\n" 107 | "OPTS:\n" 108 | " -q QUEUE send all traffic to single queue\n" 109 | " -j jhash incoming IP and ports\n" 110 | " -s jhash with Symmetric RSS\n" 111 | " -e jhash Encapsulated IPinIP headers\n" 112 | " -m QUEUES set maximum number of queues for jhash\n", 113 | prog); 114 | } 115 | 116 | int main(int argc, char **argv) 117 | { 118 | struct bpf_prog_load_attr prog_load_attr = { 119 | .prog_type = BPF_PROG_TYPE_XDP, 120 | .file = "rss_kern.o", 121 | }; 122 | struct indirect_queue indirect_rec = {}; 123 | struct queue_select_ctrl mapctrl; 124 | struct bpf_map *indirect_map; 125 | struct bpf_map *ctrl_map; 126 | struct bpf_object *obj; 127 | int queues_enabled = 0; 128 | int indirect_map_fd; 129 | int ethtool_queues; 130 | int ctrl_map_fd; 131 | int prog_fd; 132 | int key; 133 | int opt; 134 | int i; 135 | 136 | mapctrl.select_mode = QUEUE_HASH; 137 | xdp_flags = XDP_FLAGS_HW_MODE; /* set HW offload flag */ 138 | 139 | if (optind == argc) { 140 | usage(basename(argv[0])); 141 | return -1; 142 | } 143 | 144 | while ((opt = getopt(argc, argv, "hi:q:jsem:")) != -1) { 145 | switch (opt) { 146 | case 'h': 147 | usage(basename(argv[0])); 148 | return 0; 149 | case 'i': 150 | ifindex = if_nametoindex(optarg); 151 | break; 152 | case 'q': 153 | mapctrl.select_mode = QUEUE_STATIC; 154 | mapctrl.queue_static = atoi(optarg); 155 | break; 156 | case 'j': 157 | mapctrl.select_mode = QUEUE_HASH; 158 | break; 159 | case 's': 160 | mapctrl.select_mode = QUEUE_SYMMETRIC; 161 | break; 162 | case 'e': 163 | mapctrl.select_mode = QUEUE_ENCAP; 164 | break; 165 | case 'm': 166 | queues_enabled = atoi(optarg); 167 | break; 168 | default: 169 | printf("incorrect usage\n"); 170 | usage(basename(argv[0])); 171 | return -1; 172 | } 173 | } 174 | 175 | if (ifindex == 0) { 176 | printf("Err: Invalid interface\n"); 177 | return -1; 178 | } 179 | prog_load_attr.ifindex = ifindex; /* set offload dev ifindex */ 180 | 181 | ethtool_queues = get_interface_rx_channels(ifindex); 182 | if (ethtool_queues < 1) { 183 | printf("Err: Cannot obtain number of NIC channels\n"); 184 | return -1; 185 | } 186 | 187 | if (queues_enabled == 0) /* if no user defined max queue limit */ 188 | queues_enabled = ethtool_queues; 189 | 190 | if (queues_enabled > ethtool_queues) { 191 | printf("Err: Queues enabled exceeds netdev queues\n"); 192 | printf("Ethtool queues: %d\n", ethtool_queues); 193 | return -1; 194 | } 195 | 196 | if (mapctrl.select_mode == QUEUE_STATIC) { 197 | if (mapctrl.queue_static >= queues_enabled) { 198 | printf("Err: Queue selected exceeds queues enabled\n"); 199 | printf("Netdev queues enabled: %d\n", queues_enabled); 200 | return -1; 201 | } 202 | } 203 | 204 | /* use libbpf to load program */ 205 | if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) { 206 | printf("Err: Cannot load file\n"); 207 | return -1; 208 | } 209 | 210 | if (prog_fd < 1) { 211 | printf("Error creating prog_fd\n"); 212 | return -1; 213 | } 214 | 215 | signal(SIGINT, unload_prog); 216 | signal(SIGTERM, unload_prog); 217 | 218 | /* use libbpf to link program to interface with corresponding flags */ 219 | if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) { 220 | printf("Error linking fd to xdp with offload flags\n"); 221 | return -1; 222 | } 223 | 224 | ctrl_map = bpf_object__find_map_by_name(obj, "ctrl_map"); 225 | ctrl_map_fd = bpf_map__fd(ctrl_map); 226 | indirect_map = bpf_object__find_map_by_name(obj, "indirect_map"); 227 | indirect_map_fd = bpf_map__fd(indirect_map); 228 | 229 | if (!(ctrl_map_fd >= 0 && indirect_map_fd >= 0)) { 230 | printf("Err: Cannot find maps\n"); 231 | return -1; 232 | } 233 | 234 | /* fill ctrl map with hash mode queues */ 235 | key = 0; 236 | if (bpf_map_update_elem(ctrl_map_fd, &key, &mapctrl, BPF_ANY) != 0) { 237 | printf("Err: Map update\n"); 238 | return -1; 239 | } 240 | 241 | /* fill indirection map round robin using modulus */ 242 | for (i = 0; i < MAX_RSS_QUEUES; i++) { 243 | indirect_rec.queue_num = i % queues_enabled; 244 | 245 | if (bpf_map_update_elem(indirect_map_fd, &i, &indirect_rec, 246 | BPF_ANY) != 0) { 247 | printf("Err: Map update failed\n"); 248 | return -1; 249 | } 250 | } 251 | poll_stats(indirect_map_fd, queues_enabled, 1); 252 | return 0; 253 | } 254 | -------------------------------------------------------------------------------- /programmable_rss/traffic_IPIP.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Netronome/bpf-samples/a7dd7d8c38636dd0a1bb5f2380ce309f314abfe3/programmable_rss/traffic_IPIP.pcap -------------------------------------------------------------------------------- /xdpdump/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | 3 | TARGET := xdpdump 4 | 5 | LLC ?= llc 6 | CLANG ?= clang 7 | CC ?= gcc 8 | 9 | LIBBPF_DIR = ../libbpf/src/ 10 | 11 | XDP_C = ${TARGET:=_kern.c} 12 | XDP_OBJ = ${XDP_C:.c=.o} 13 | USER_C = ${TARGET:=_user.c} 14 | USER_OBJ = ${USER_C:.c=.o} 15 | OBJECT_LIBBPF = $(LIBBPF_DIR)/libbpf.a 16 | 17 | CFLAGS ?= -I$(LIBBPF_DIR)/root/usr/include/ 18 | CFLAGS += -I../headers/ 19 | LDFLAGS ?= -L$(LIBBPF_DIR) 20 | 21 | LIBS = -lbpf -lelf 22 | 23 | all: llvm-check $(TARGET) $(XDP_OBJ) 24 | 25 | .PHONY: clean $(CLANG) $(LLC) 26 | 27 | clean: 28 | cd $(LIBBPF_DIR) && $(MAKE) clean; 29 | rm -f $(TARGET) 30 | rm -f $(XDP_OBJ) 31 | rm -f $(USER_OBJ) 32 | rm -f *.ll 33 | 34 | llvm-check: $(CLANG) $(LLC) 35 | @for TOOL in $^ ; do \ 36 | if [ ! $$(command -v $${TOOL} 2>/dev/null) ]; then \ 37 | echo "*** ERROR: Cannot find tool $${TOOL}" ;\ 38 | exit 1; \ 39 | else true; fi; \ 40 | done 41 | 42 | $(OBJECT_LIBBPF): 43 | @if [ ! -d $(LIBBPF_DIR) ]; then \ 44 | echo "Error: Need libbpf submodule"; \ 45 | echo "May need to run git submodule update --init"; \ 46 | exit 1; \ 47 | else \ 48 | cd $(LIBBPF_DIR) && $(MAKE) all; \ 49 | mkdir -p root; DESTDIR=root $(MAKE) install_headers; \ 50 | fi 51 | 52 | $(TARGET): %: %_user.c $(OBJECT_LIBBPF) Makefile 53 | $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) 54 | 55 | $(XDP_OBJ): %.o: %.c 56 | $(CLANG) -S \ 57 | -D __BPF_TRACING__ \ 58 | $(CFLAGS) \ 59 | -Wall \ 60 | -Wno-unused-value \ 61 | -Wno-pointer-sign \ 62 | -Wno-compare-distinct-pointer-types \ 63 | -Werror \ 64 | -O2 -emit-llvm -c -g $< 65 | $(LLC) -march=bpf -filetype=obj -o $@ ${@:.o=.ll} 66 | -------------------------------------------------------------------------------- /xdpdump/README.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | 3 | xdpdump Demo 4 | ============ 5 | 6 | Demo App 7 | ~~~~~~~~ 8 | 9 | This program demonstrates how a eBPF program may communicate with userspace 10 | using the kernel's perf tracing events. 11 | 12 | The demo's userspace program creates a perf ring buffer for each of the host's 13 | CPUs. This ring buffer is assigned a File Descriptor, this is subsequently 14 | written to the eBPF map, denoted by the CPU index. 15 | 16 | When an ingress packet enters the XDP program, packet metadata is extracted and 17 | stored into a data structure. The XDP program sends this metadata, along with 18 | the packet contents to the ring buffer denoted in the eBPF perf event map using 19 | the current CPU index as the key. 20 | 21 | The userspace program polls the perf rings for events from the XDP program. 22 | When an event is received, it prints the event's metadata to the terminal. 23 | The user can also specify if the packet contents should be dumped in hexadecimal 24 | format. 25 | 26 | This demo program can currently only analyze IPv4 and IPv6 packets containing 27 | TCP/UDP data, but could easily be expanded to cover a wider range of protocols. 28 | 29 | Minimum Requirements for Demo 30 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 | 32 | - Linux kernel 4.18 33 | - clang / LLVM 4.0 34 | - libelf-dev (Ubuntu) / elfutils-devel (Fedora) 35 | - Agilio® eBPF firmware for HW offload 36 | (available from `Netronome's support website`_) 37 | 38 | .. _Netronome's support website: https://help.netronome.com/ 39 | 40 | Loading the Demo 41 | ~~~~~~~~~~~~~~~~ 42 | 43 | The program is compiled using an included libbpf. To compile the user space and 44 | XDP programs :: 45 | 46 | $ make 47 | 48 | To load the program :: 49 | 50 | # ./xdpdump -i INTERFACE 51 | 52 | Examples 53 | ~~~~~~~~ 54 | 55 | The program may be started in driver mode using the following command :: 56 | 57 | # ./xdpdump -i eth4 58 | ----------------------------------------------------------------------- 59 | 28228.714182 IP 10.0.0.2:9203 > 10.0.0.1:0 TCP seq 437136853, length 6 60 | 28233.714510 IP6 fe80::268a:7ff:fe3b:46:9 > 2001:db8:85a3::370:7334:9 UDP, length 16 61 | 28234.040118 IP 10.0.0.2:1709 > 10.0.0.1:0 TCP seq 1723695364, length 30 62 | 63 | Payload information can also be displayed with the payload option :: 64 | 65 | # ./xdpdump -i eth4 -x 66 | --------------------------------------------------------- 67 | 28298.719497 IP 10.0.0.2:1697 > 10.0.0.1:0 TCP seq 1017625101, length 6 68 | 0015 4d13 0880 248a 073b 0046 0800 4500 69 | 0028 18fa 0000 4006 4dd4 0a00 0002 0a00 70 | 0001 06a1 0000 3ca7 ba0d 558d d5a8 5000 71 | 0200 7156 0000 0000 0000 0000 72 | 73 | The program may be offloaded to the SmartNIC using the HW offload option :: 74 | 75 | # ./xdpdump -i eth4 -x -H 76 | --------------------------------------------------------- 77 | 28357.729517 IP 10.0.0.2:54013 > 10.0.0.1:53 UDP, length 51 78 | 0015 4d13 0880 248a 073b 0046 0800 4500 79 | 004f cf83 0000 4011 9718 0a00 0002 0a00 80 | 0001 d2fd 0035 003b bd51 cd62 0120 0001 81 | 0000 0000 0001 0667 6f6f 676c 6503 636f 82 | 6d00 0001 0001 0000 2910 0000 0000 0000 83 | 0c00 0a00 08ce 1722 411e 4e95 8b 84 | 85 | For systems without a compatible XDP driver, it can also be loaded in SKB mode :: 86 | 87 | # ./xdpdump -i eth4 -S 88 | 89 | Removing the Demo 90 | ~~~~~~~~~~~~~~~~~ 91 | 92 | The XDP program will automatically be unloaded on exiting the xdpdump program 93 | -------------------------------------------------------------------------------- /xdpdump/xdpdump_common.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */ 2 | /* Copyright (c) 2018 Netronome Systems, Inc. */ 3 | 4 | #define MAX_CPU 128 5 | 6 | struct pkt_meta { 7 | union { 8 | __be32 src; 9 | __be32 srcv6[4]; 10 | }; 11 | union { 12 | __be32 dst; 13 | __be32 dstv6[4]; 14 | }; 15 | __u16 port16[2]; 16 | __u16 l3_proto; 17 | __u16 l4_proto; 18 | __u16 data_len; 19 | __u16 pkt_len; 20 | __u32 seq; 21 | }; 22 | -------------------------------------------------------------------------------- /xdpdump/xdpdump_kern.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | // Copyright (c) 2018 Netronome Systems, Inc. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "bpf_endian.h" 15 | #include "bpf_helpers.h" 16 | #include "xdpdump_common.h" 17 | 18 | struct bpf_map_def SEC("maps") perf_map = { 19 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 20 | .key_size = sizeof(__u32), 21 | .value_size = sizeof(__u32), 22 | .max_entries = MAX_CPU, 23 | }; 24 | 25 | static __always_inline bool parse_udp(void *data, __u64 off, void *data_end, 26 | struct pkt_meta *pkt) 27 | { 28 | struct udphdr *udp; 29 | 30 | udp = data + off; 31 | if (udp + 1 > data_end) 32 | return false; 33 | 34 | pkt->port16[0] = udp->source; 35 | pkt->port16[1] = udp->dest; 36 | return true; 37 | } 38 | 39 | static __always_inline bool parse_tcp(void *data, __u64 off, void *data_end, 40 | struct pkt_meta *pkt) 41 | { 42 | struct tcphdr *tcp; 43 | 44 | tcp = data + off; 45 | if (tcp + 1 > data_end) 46 | return false; 47 | 48 | pkt->port16[0] = tcp->source; 49 | pkt->port16[1] = tcp->dest; 50 | pkt->seq = tcp->seq; 51 | 52 | return true; 53 | } 54 | 55 | static __always_inline bool parse_ip4(void *data, __u64 off, void *data_end, 56 | struct pkt_meta *pkt) 57 | { 58 | struct iphdr *iph; 59 | 60 | iph = data + off; 61 | if (iph + 1 > data_end) 62 | return false; 63 | 64 | if (iph->ihl != 5) 65 | return false; 66 | 67 | pkt->src = iph->saddr; 68 | pkt->dst = iph->daddr; 69 | pkt->l4_proto = iph->protocol; 70 | 71 | return true; 72 | } 73 | 74 | static __always_inline bool parse_ip6(void *data, __u64 off, void *data_end, 75 | struct pkt_meta *pkt) 76 | { 77 | struct ipv6hdr *ip6h; 78 | 79 | ip6h = data + off; 80 | if (ip6h + 1 > data_end) 81 | return false; 82 | 83 | memcpy(pkt->srcv6, ip6h->saddr.s6_addr32, 16); 84 | memcpy(pkt->dstv6, ip6h->daddr.s6_addr32, 16); 85 | pkt->l4_proto = ip6h->nexthdr; 86 | 87 | return true; 88 | } 89 | 90 | SEC("xdp") 91 | int process_packet(struct xdp_md *ctx) 92 | { 93 | void *data_end = (void *)(long)ctx->data_end; 94 | void *data = (void *)(long)ctx->data; 95 | struct ethhdr *eth = data; 96 | struct pkt_meta pkt = {}; 97 | __u32 off; 98 | 99 | /* parse packet for IP Addresses and Ports */ 100 | off = sizeof(struct ethhdr); 101 | if (data + off > data_end) 102 | return XDP_PASS; 103 | 104 | pkt.l3_proto = bpf_htons(eth->h_proto); 105 | 106 | if (pkt.l3_proto == ETH_P_IP) { 107 | if (!parse_ip4(data, off, data_end, &pkt)) 108 | return XDP_PASS; 109 | off += sizeof(struct iphdr); 110 | } else if (pkt.l3_proto == ETH_P_IPV6) { 111 | if (!parse_ip6(data, off, data_end, &pkt)) 112 | return XDP_PASS; 113 | off += sizeof(struct ipv6hdr); 114 | } 115 | 116 | if (data + off > data_end) 117 | return XDP_PASS; 118 | 119 | /* obtain port numbers for UDP and TCP traffic */ 120 | if (pkt.l4_proto == IPPROTO_TCP) { 121 | if (!parse_tcp(data, off, data_end, &pkt)) 122 | return XDP_PASS; 123 | off += sizeof(struct tcphdr); 124 | } else if (pkt.l4_proto == IPPROTO_UDP) { 125 | if (!parse_udp(data, off, data_end, &pkt)) 126 | return XDP_PASS; 127 | off += sizeof(struct udphdr); 128 | } else { 129 | pkt.port16[0] = 0; 130 | pkt.port16[1] = 0; 131 | } 132 | 133 | pkt.pkt_len = data_end - data; 134 | pkt.data_len = data_end - data - off; 135 | 136 | bpf_perf_event_output(ctx, &perf_map, 137 | (__u64)pkt.pkt_len << 32 | BPF_F_CURRENT_CPU, 138 | &pkt, sizeof(pkt)); 139 | return XDP_PASS; 140 | } 141 | 142 | char _license[] SEC("license") = "Dual BSD/GPL"; 143 | -------------------------------------------------------------------------------- /xdpdump/xdpdump_user.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 | // Copyright (c) 2018 Netronome Systems, Inc. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "xdpdump_common.h" 22 | 23 | #define NS_IN_SEC 1000000000 24 | #define PAGE_CNT 8 25 | 26 | struct perf_event_sample { 27 | struct perf_event_header header; 28 | __u64 timestamp; 29 | __u32 size; 30 | struct pkt_meta meta; 31 | __u8 pkt_data[64]; 32 | }; 33 | 34 | static __u32 xdp_flags; 35 | static int ifindex; 36 | bool dump_payload; 37 | 38 | static void unload_prog(int sig) 39 | { 40 | bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); 41 | printf("unloading xdp program...\n"); 42 | exit(0); 43 | } 44 | 45 | void meta_print(struct pkt_meta meta, __u64 timestamp) 46 | { 47 | char src_str[INET6_ADDRSTRLEN]; 48 | char dst_str[INET6_ADDRSTRLEN]; 49 | char l3_str[32]; 50 | char l4_str[32]; 51 | 52 | switch (meta.l3_proto) { 53 | case ETH_P_IP: 54 | strcpy(l3_str, "IP"); 55 | inet_ntop(AF_INET, &meta.src, src_str, INET_ADDRSTRLEN); 56 | inet_ntop(AF_INET, &meta.dst, dst_str, INET_ADDRSTRLEN); 57 | break; 58 | case ETH_P_IPV6: 59 | strcpy(l3_str, "IP6"); 60 | inet_ntop(AF_INET6, &meta.srcv6, src_str, INET6_ADDRSTRLEN); 61 | inet_ntop(AF_INET6, &meta.dstv6, dst_str, INET6_ADDRSTRLEN); 62 | break; 63 | case ETH_P_ARP: 64 | strcpy(l3_str, "ARP"); 65 | break; 66 | default: 67 | sprintf(l3_str, "%04x", meta.l3_proto); 68 | } 69 | 70 | switch (meta.l4_proto) { 71 | case IPPROTO_TCP: 72 | sprintf(l4_str, "TCP seq %d", ntohl(meta.seq)); 73 | break; 74 | case IPPROTO_UDP: 75 | strcpy(l4_str, "UDP"); 76 | break; 77 | case IPPROTO_ICMP: 78 | strcpy(l4_str, "ICMP"); 79 | break; 80 | default: 81 | strcpy(l4_str, ""); 82 | } 83 | 84 | printf("%lld.%06lld %s %s:%d > %s:%d %s, length %d\n", 85 | timestamp / NS_IN_SEC, (timestamp % NS_IN_SEC) / 1000, 86 | l3_str, 87 | src_str, ntohs(meta.port16[0]), 88 | dst_str, ntohs(meta.port16[1]), 89 | l4_str, meta.data_len); 90 | } 91 | 92 | int event_printer(struct perf_event_sample *sample) 93 | { 94 | int i; 95 | 96 | meta_print(sample->meta, sample->timestamp); 97 | 98 | if (dump_payload) { /* print payload hex */ 99 | printf("\t"); 100 | for (i = 0; i < sample->meta.pkt_len; i++) { 101 | printf("%02x", sample->pkt_data[i]); 102 | 103 | if ((i + 1) % 16 == 0) 104 | printf("\n\t"); 105 | else if ((i + 1) % 2 == 0) 106 | printf(" "); 107 | } 108 | printf("\n"); 109 | } 110 | return LIBBPF_PERF_EVENT_CONT; 111 | } 112 | 113 | static enum bpf_perf_event_ret event_received(void *event, void *printfn) 114 | { 115 | int (*print_fn)(struct perf_event_sample *) = printfn; 116 | struct perf_event_sample *sample = event; 117 | 118 | if (sample->header.type == PERF_RECORD_SAMPLE) 119 | return print_fn(sample); 120 | else 121 | return LIBBPF_PERF_EVENT_CONT; 122 | } 123 | 124 | int event_poller(struct perf_event_mmap_page **mem_buf, int *sys_fds, 125 | int cpu_total) 126 | { 127 | struct pollfd poll_fds[MAX_CPU]; 128 | void *buf = NULL; 129 | size_t len = 0; 130 | int total_size; 131 | int pagesize; 132 | int res; 133 | int n; 134 | 135 | /* Create pollfd struct to contain poller info */ 136 | for (n = 0; n < cpu_total; n++) { 137 | poll_fds[n].fd = sys_fds[n]; 138 | poll_fds[n].events = POLLIN; 139 | } 140 | 141 | pagesize = getpagesize(); 142 | total_size = PAGE_CNT * pagesize; 143 | for (;;) { 144 | /* Poll fds for events, 250ms timeout */ 145 | poll(poll_fds, cpu_total, 250); 146 | 147 | for (n = 0; n < cpu_total; n++) { 148 | if (poll_fds[n].revents) { /* events found */ 149 | res = bpf_perf_event_read_simple(mem_buf[n], 150 | total_size, 151 | pagesize, 152 | &buf, &len, 153 | event_received, 154 | event_printer); 155 | if (res != LIBBPF_PERF_EVENT_CONT) 156 | break; 157 | } 158 | } 159 | } 160 | free(buf); 161 | } 162 | 163 | int setup_perf_poller(int perf_map_fd, int *sys_fds, int cpu_total, 164 | struct perf_event_mmap_page **mem_buf) 165 | { 166 | struct perf_event_attr attr = { 167 | .sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME, 168 | .type = PERF_TYPE_SOFTWARE, 169 | .config = PERF_COUNT_SW_BPF_OUTPUT, 170 | .wakeup_events = 1, 171 | }; 172 | int mmap_size; 173 | int pmu; 174 | int n; 175 | 176 | mmap_size = getpagesize() * (PAGE_CNT + 1); 177 | 178 | for (n = 0; n < cpu_total; n++) { 179 | /* create perf fd for each thread */ 180 | pmu = sys_perf_event_open(&attr, -1, n, -1, 0); 181 | if (pmu < 0) { 182 | printf("error setting up perf fd\n"); 183 | return 1; 184 | } 185 | /* enable PERF events on the fd */ 186 | ioctl(pmu, PERF_EVENT_IOC_ENABLE, 0); 187 | 188 | /* give fd a memory buf to write to */ 189 | mem_buf[n] = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, 190 | MAP_SHARED, pmu, 0); 191 | if (mem_buf[n] == MAP_FAILED) { 192 | printf("error creating mmap\n"); 193 | return 1; 194 | } 195 | /* point eBPF map entries to fd */ 196 | assert(!bpf_map_update_elem(perf_map_fd, &n, &pmu, BPF_ANY)); 197 | sys_fds[n] = pmu; 198 | } 199 | return 0; 200 | } 201 | 202 | static void usage(const char *prog) 203 | { 204 | fprintf(stderr, 205 | "%s -i interface [OPTS]\n\n" 206 | "OPTS:\n" 207 | " -h help\n" 208 | " -H Hardware Mode (XDPOFFLOAD)\n" 209 | " -N Native Mode (XDPDRV)\n" 210 | " -S SKB Mode (XDPGENERIC)\n" 211 | " -x Show packet payload\n", 212 | prog); 213 | } 214 | 215 | int main(int argc, char **argv) 216 | { 217 | static struct perf_event_mmap_page *mem_buf[MAX_CPU]; 218 | struct bpf_prog_load_attr prog_load_attr = { 219 | .prog_type = BPF_PROG_TYPE_XDP, 220 | .file = "xdpdump_kern.o", 221 | }; 222 | struct bpf_map *perf_map; 223 | struct bpf_object *obj; 224 | int sys_fds[MAX_CPU]; 225 | int perf_map_fd; 226 | int prog_fd; 227 | int n_cpus; 228 | int opt; 229 | 230 | xdp_flags = XDP_FLAGS_DRV_MODE; /* default to DRV */ 231 | n_cpus = get_nprocs(); 232 | dump_payload = 0; 233 | 234 | if (optind == argc) { 235 | usage(basename(argv[0])); 236 | return -1; 237 | } 238 | 239 | while ((opt = getopt(argc, argv, "hHi:NSx")) != -1) { 240 | switch (opt) { 241 | case 'h': 242 | usage(basename(argv[0])); 243 | return 0; 244 | case 'H': 245 | xdp_flags = XDP_FLAGS_HW_MODE; 246 | prog_load_attr.ifindex = ifindex; /* set HW ifindex */ 247 | break; 248 | case 'i': 249 | ifindex = if_nametoindex(optarg); 250 | break; 251 | case 'N': 252 | xdp_flags = XDP_FLAGS_DRV_MODE; 253 | break; 254 | case 'S': 255 | xdp_flags = XDP_FLAGS_SKB_MODE; 256 | break; 257 | case 'x': 258 | dump_payload = 1; 259 | break; 260 | default: 261 | printf("incorrect usage\n"); 262 | usage(basename(argv[0])); 263 | return -1; 264 | } 265 | } 266 | 267 | if (ifindex == 0) { 268 | printf("error, invalid interface\n"); 269 | return -1; 270 | } 271 | 272 | /* use libbpf to load program */ 273 | if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) { 274 | printf("error with loading file\n"); 275 | return -1; 276 | } 277 | 278 | if (prog_fd < 1) { 279 | printf("error creating prog_fd\n"); 280 | return -1; 281 | } 282 | 283 | signal(SIGINT, unload_prog); 284 | signal(SIGTERM, unload_prog); 285 | 286 | /* use libbpf to link program to interface with corresponding flags */ 287 | if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) { 288 | printf("error setting fd onto xdp\n"); 289 | return -1; 290 | } 291 | 292 | perf_map = bpf_object__find_map_by_name(obj, "perf_map"); 293 | perf_map_fd = bpf_map__fd(perf_map); 294 | 295 | if (perf_map_fd < 0) { 296 | printf("error cannot find map\n"); 297 | return -1; 298 | } 299 | 300 | /* Initialize perf rings */ 301 | if (setup_perf_poller(perf_map_fd, sys_fds, n_cpus, &mem_buf[0])) 302 | return -1; 303 | 304 | event_poller(mem_buf, sys_fds, n_cpus); 305 | 306 | return 0; 307 | } 308 | --------------------------------------------------------------------------------