├── Contributors.md ├── LICENSE ├── README.md ├── changelog.md └── code ├── .gitignore ├── include ├── bits.bpf.h ├── tcp_int_common.bpf.h ├── tcp_int_common.h └── tcp_int_opt.h ├── scripts ├── clang_style_format.sh ├── collect_client_stats.sh ├── collect_server_stats.sh ├── gofmt_style_indent.sh ├── namespaces.sh ├── run_ss.sh └── tcp-int-run ├── src ├── Makefile ├── bpf │ └── tcp_int.bpf.c └── tools │ ├── tcp_int.c │ └── tcp_int.h └── tcp-int-exporter └── src ├── models ├── go.mod ├── go.sum └── proto │ ├── README.md │ ├── exporter.proto │ └── generate.sh └── tcp_int_exporter ├── Makefile ├── README.md ├── go.mod ├── go.sum ├── main.go ├── pkg ├── exporter │ └── tcp_int_exporter.go ├── global │ └── global.go ├── parser │ └── parser.go └── secure │ └── secure.go └── utils └── utils.go /Contributors.md: -------------------------------------------------------------------------------- 1 | # This is the list of TCP-INT's contributors. 2 | 3 | Bimmy Pujari 4 | Grzegorz Jereczek 5 | Jeongkeun Lee contributed to design/algorithms 6 | Simon Wass 7 | Theo Jepsen 8 | ... 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | All files in this project are: 2 | 3 | Copyright (c) Intel Corporation or Copyright 2021 Intel Corporation. 4 | All rights reserved. 5 | 6 | The files containing Copyright Intel Corporation and the 7 | following SPDX-License-Identifier line in a comment near the beginning: 8 | 9 | SPDX-License-Identifier: Apache-2.0 10 | 11 | are distributed under the Apache license shown below. 12 | 13 | 14 | The files containing Copyright (c) Intel Corporation and the 15 | following SPDX-License-Identifier line in a comment near the beginning: 16 | 17 | SPDX-License-Identifier: GPL-2.0-only 18 | 19 | are distributed under the GNU General Public License, version 2. 20 | 21 | 22 | The files containing Copyright (c) Intel Corporation and the 23 | following SPDX-License-Identifier line in a comment near the beginning: 24 | 25 | SPDX-License-Identifier: BSD-2-Clause 26 | 27 | are distributed under the BSD license shown below. 28 | 29 | 30 | --------------------------------------------------------------------------- 31 | https://spdx.org/licenses/Apache-2.0.html 32 | --------------------------------------------------------------------------- 33 | Apache License 34 | Version 2.0, January 2004 35 | http://www.apache.org/licenses/ 36 | 37 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 38 | 39 | 1. Definitions. 40 | 41 | "License" shall mean the terms and conditions for use, reproduction, 42 | and distribution as defined by Sections 1 through 9 of this document. 43 | 44 | "Licensor" shall mean the copyright owner or entity authorized by 45 | the copyright owner that is granting the License. 46 | 47 | "Legal Entity" shall mean the union of the acting entity and all 48 | other entities that control, are controlled by, or are under common 49 | control with that entity. For the purposes of this definition, 50 | "control" means (i) the power, direct or indirect, to cause the 51 | direction or management of such entity, whether by contract or 52 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 53 | outstanding shares, or (iii) beneficial ownership of such entity. 54 | 55 | "You" (or "Your") shall mean an individual or Legal Entity 56 | exercising permissions granted by this License. 57 | 58 | "Source" form shall mean the preferred form for making modifications, 59 | including but not limited to software source code, documentation 60 | source, and configuration files. 61 | 62 | "Object" form shall mean any form resulting from mechanical 63 | transformation or translation of a Source form, including but 64 | not limited to compiled object code, generated documentation, 65 | and conversions to other media types. 66 | 67 | "Work" shall mean the work of authorship, whether in Source or 68 | Object form, made available under the License, as indicated by a 69 | copyright notice that is included in or attached to the work 70 | (an example is provided in the Appendix below). 71 | 72 | "Derivative Works" shall mean any work, whether in Source or Object 73 | form, that is based on (or derived from) the Work and for which the 74 | editorial revisions, annotations, elaborations, or other modifications 75 | represent, as a whole, an original work of authorship. For the purposes 76 | of this License, Derivative Works shall not include works that remain 77 | separable from, or merely link (or bind by name) to the interfaces of, 78 | the Work and Derivative Works thereof. 79 | 80 | "Contribution" shall mean any work of authorship, including 81 | the original version of the Work and any modifications or additions 82 | to that Work or Derivative Works thereof, that is intentionally 83 | submitted to Licensor for inclusion in the Work by the copyright owner 84 | or by an individual or Legal Entity authorized to submit on behalf of 85 | the copyright owner. For the purposes of this definition, "submitted" 86 | means any form of electronic, verbal, or written communication sent 87 | to the Licensor or its representatives, including but not limited to 88 | communication on electronic mailing lists, source code control systems, 89 | and issue tracking systems that are managed by, or on behalf of, the 90 | Licensor for the purpose of discussing and improving the Work, but 91 | excluding communication that is conspicuously marked or otherwise 92 | designated in writing by the copyright owner as "Not a Contribution." 93 | 94 | "Contributor" shall mean Licensor and any individual or Legal Entity 95 | on behalf of whom a Contribution has been received by Licensor and 96 | subsequently incorporated within the Work. 97 | 98 | 2. Grant of Copyright License. Subject to the terms and conditions of 99 | this License, each Contributor hereby grants to You a perpetual, 100 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 101 | copyright license to reproduce, prepare Derivative Works of, 102 | publicly display, publicly perform, sublicense, and distribute the 103 | Work and such Derivative Works in Source or Object form. 104 | 105 | 3. Grant of Patent License. Subject to the terms and conditions of 106 | this License, each Contributor hereby grants to You a perpetual, 107 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 108 | (except as stated in this section) patent license to make, have made, 109 | use, offer to sell, sell, import, and otherwise transfer the Work, 110 | where such license applies only to those patent claims licensable 111 | by such Contributor that are necessarily infringed by their 112 | Contribution(s) alone or by combination of their Contribution(s) 113 | with the Work to which such Contribution(s) was submitted. If You 114 | institute patent litigation against any entity (including a 115 | cross-claim or counterclaim in a lawsuit) alleging that the Work 116 | or a Contribution incorporated within the Work constitutes direct 117 | or contributory patent infringement, then any patent licenses 118 | granted to You under this License for that Work shall terminate 119 | as of the date such litigation is filed. 120 | 121 | 4. Redistribution. You may reproduce and distribute copies of the 122 | Work or Derivative Works thereof in any medium, with or without 123 | modifications, and in Source or Object form, provided that You 124 | meet the following conditions: 125 | 126 | (a) You must give any other recipients of the Work or 127 | Derivative Works a copy of this License; and 128 | 129 | (b) You must cause any modified files to carry prominent notices 130 | stating that You changed the files; and 131 | 132 | (c) You must retain, in the Source form of any Derivative Works 133 | that You distribute, all copyright, patent, trademark, and 134 | attribution notices from the Source form of the Work, 135 | excluding those notices that do not pertain to any part of 136 | the Derivative Works; and 137 | 138 | (d) If the Work includes a "NOTICE" text file as part of its 139 | distribution, then any Derivative Works that You distribute must 140 | include a readable copy of the attribution notices contained 141 | within such NOTICE file, excluding those notices that do not 142 | pertain to any part of the Derivative Works, in at least one 143 | of the following places: within a NOTICE text file distributed 144 | as part of the Derivative Works; within the Source form or 145 | documentation, if provided along with the Derivative Works; or, 146 | within a display generated by the Derivative Works, if and 147 | wherever such third-party notices normally appear. The contents 148 | of the NOTICE file are for informational purposes only and 149 | do not modify the License. You may add Your own attribution 150 | notices within Derivative Works that You distribute, alongside 151 | or as an addendum to the NOTICE text from the Work, provided 152 | that such additional attribution notices cannot be construed 153 | as modifying the License. 154 | 155 | You may add Your own copyright statement to Your modifications and 156 | may provide additional or different license terms and conditions 157 | for use, reproduction, or distribution of Your modifications, or 158 | for any such Derivative Works as a whole, provided Your use, 159 | reproduction, and distribution of the Work otherwise complies with 160 | the conditions stated in this License. 161 | 162 | 5. Submission of Contributions. Unless You explicitly state otherwise, 163 | any Contribution intentionally submitted for inclusion in the Work 164 | by You to the Licensor shall be under the terms and conditions of 165 | this License, without any additional terms or conditions. 166 | Notwithstanding the above, nothing herein shall supersede or modify 167 | the terms of any separate license agreement you may have executed 168 | with Licensor regarding such Contributions. 169 | 170 | 6. Trademarks. This License does not grant permission to use the trade 171 | names, trademarks, service marks, or product names of the Licensor, 172 | except as required for reasonable and customary use in describing the 173 | origin of the Work and reproducing the content of the NOTICE file. 174 | 175 | 7. Disclaimer of Warranty. Unless required by applicable law or 176 | agreed to in writing, Licensor provides the Work (and each 177 | Contributor provides its Contributions) on an "AS IS" BASIS, 178 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 179 | implied, including, without limitation, any warranties or conditions 180 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 181 | PARTICULAR PURPOSE. You are solely responsible for determining the 182 | appropriateness of using or redistributing the Work and assume any 183 | risks associated with Your exercise of permissions under this License. 184 | 185 | 8. Limitation of Liability. In no event and under no legal theory, 186 | whether in tort (including negligence), contract, or otherwise, 187 | unless required by applicable law (such as deliberate and grossly 188 | negligent acts) or agreed to in writing, shall any Contributor be 189 | liable to You for damages, including any direct, indirect, special, 190 | incidental, or consequential damages of any character arising as a 191 | result of this License or out of the use or inability to use the 192 | Work (including but not limited to damages for loss of goodwill, 193 | work stoppage, computer failure or malfunction, or any and all 194 | other commercial damages or losses), even if such Contributor 195 | has been advised of the possibility of such damages. 196 | 197 | 9. Accepting Warranty or Additional Liability. While redistributing 198 | the Work or Derivative Works thereof, You may choose to offer, 199 | and charge a fee for, acceptance of support, warranty, indemnity, 200 | or other liability obligations and/or rights consistent with this 201 | License. However, in accepting such obligations, You may act only 202 | on Your own behalf and on Your sole responsibility, not on behalf 203 | of any other Contributor, and only if You agree to indemnify, 204 | defend, and hold each Contributor harmless for any liability 205 | incurred by, or claims asserted against, such Contributor by reason 206 | of your accepting any such warranty or additional liability. 207 | 208 | END OF TERMS AND CONDITIONS 209 | ---------------------------------------------------------------------- 210 | 211 | 212 | ---------------------------------------------------------------------- 213 | https://spdx.org/licenses/GPL-2.0-only.html 214 | ---------------------------------------------------------------------- 215 | GNU GENERAL PUBLIC LICENSE 216 | Version 2, June 1991 217 | 218 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 219 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 220 | 221 | Everyone is permitted to copy and distribute verbatim copies of this 222 | license document, but changing it is not allowed. 223 | 224 | Preamble 225 | 226 | The licenses for most software are designed to take away your freedom 227 | to share and change it. By contrast, the GNU General Public License is 228 | intended to guarantee your freedom to share and change free 229 | software--to make sure the software is free for all its users. This 230 | General Public License applies to most of the Free Software 231 | Foundation's software and to any other program whose authors commit to 232 | using it. (Some other Free Software Foundation software is covered by 233 | the GNU Library General Public License instead.) You can apply it to 234 | your programs, too. 235 | 236 | When we speak of free software, we are referring to freedom, not 237 | price. Our General Public Licenses are designed to make sure that you 238 | have the freedom to distribute copies of free software (and charge for 239 | this service if you wish), that you receive source code or can get it 240 | if you want it, that you can change the software or use pieces of it 241 | in new free programs; and that you know you can do these things. 242 | 243 | To protect your rights, we need to make restrictions that forbid 244 | anyone to deny you these rights or to ask you to surrender the 245 | rights. These restrictions translate to certain responsibilities for 246 | you if you distribute copies of the software, or if you modify it. 247 | 248 | For example, if you distribute copies of such a program, whether 249 | gratis or for a fee, you must give the recipients all the rights that 250 | you have. You must make sure that they, too, receive or can get the 251 | source code. And you must show them these terms so they know their 252 | rights. 253 | 254 | We protect your rights with two steps: (1) copyright the software, and 255 | (2) offer you this license which gives you legal permission to copy, 256 | distribute and/or modify the software. 257 | 258 | Also, for each author's protection and ours, we want to make certain 259 | that everyone understands that there is no warranty for this free 260 | software. If the software is modified by someone else and passed on, 261 | we want its recipients to know that what they have is not the 262 | original, so that any problems introduced by others will not reflect 263 | on the original authors' reputations. 264 | 265 | Finally, any free program is threatened constantly by software 266 | patents. We wish to avoid the danger that redistributors of a free 267 | program will individually obtain patent licenses, in effect making the 268 | program proprietary. To prevent this, we have made it clear that any 269 | patent must be licensed for everyone's free use or not licensed at 270 | all. 271 | 272 | The precise terms and conditions for copying, distribution and 273 | modification follow. 274 | 275 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 276 | 277 | 0. This License applies to any program or other work which contains a 278 | notice placed by the copyright holder saying it may be distributed 279 | under the terms of this General Public License. The "Program", below, 280 | refers to any such program or work, and a "work based on the Program" 281 | means either the Program or any derivative work under copyright law: 282 | that is to say, a work containing the Program or a portion of it, 283 | either verbatim or with modifications and/or translated into another 284 | language. (Hereinafter, translation is included without limitation in 285 | the term "modification".) Each licensee is addressed as "you". 286 | 287 | Activities other than copying, distribution and modification are not 288 | covered by this License; they are outside its scope. The act of 289 | running the Program is not restricted, and the output from the Program 290 | is covered only if its contents constitute a work based on the Program 291 | (independent of having been made by running the Program). Whether that 292 | is true depends on what the Program does. 293 | 294 | 1. You may copy and distribute verbatim copies of the Program's source 295 | code as you receive it, in any medium, provided that you conspicuously 296 | and appropriately publish on each copy an appropriate copyright notice 297 | and disclaimer of warranty; keep intact all the notices that refer to 298 | this License and to the absence of any warranty; and give any other 299 | recipients of the Program a copy of this License along with the 300 | Program. 301 | 302 | You may charge a fee for the physical act of transferring a copy, and 303 | you may at your option offer warranty protection in exchange for a 304 | fee. 305 | 306 | 2. You may modify your copy or copies of the Program or any portion of 307 | it, thus forming a work based on the Program, and copy and distribute 308 | such modifications or work under the terms of Section 1 above, 309 | provided that you also meet all of these conditions: 310 | 311 | a) You must cause the modified files to carry prominent notices 312 | stating that you changed the files and the date of any change. 313 | 314 | b) You must cause any work that you distribute or publish, that in 315 | whole or in part contains or is derived from the Program or any part 316 | thereof, to be licensed as a whole at no charge to all third parties 317 | under the terms of this License. 318 | 319 | c) If the modified program normally reads commands interactively when 320 | run, you must cause it, when started running for such interactive use 321 | in the most ordinary way, to print or display an announcement 322 | including an appropriate copyright notice and a notice that there is 323 | no warranty (or else, saying that you provide a warranty) and that 324 | users may redistribute the program under these conditions, and telling 325 | the user how to view a copy of this License. (Exception: if the 326 | Program itself is interactive but does not normally print such an 327 | announcement, your work based on the Program is not required to print 328 | an announcement.) 329 | 330 | These requirements apply to the modified work as a whole. If 331 | identifiable sections of that work are not derived from the Program, 332 | and can be reasonably considered independent and separate works in 333 | themselves, then this License, and its terms, do not apply to those 334 | sections when you distribute them as separate works. But when you 335 | distribute the same sections as part of a whole which is a work based 336 | on the Program, the distribution of the whole must be on the terms of 337 | this License, whose permissions for other licensees extend to the 338 | entire whole, and thus to each and every part regardless of who wrote 339 | it. 340 | 341 | Thus, it is not the intent of this section to claim rights or contest 342 | your rights to work written entirely by you; rather, the intent is to 343 | exercise the right to control the distribution of derivative or 344 | collective works based on the Program. 345 | 346 | In addition, mere aggregation of another work not based on the Program 347 | with the Program (or with a work based on the Program) on a volume of 348 | a storage or distribution medium does not bring the other work under 349 | the scope of this License. 350 | 351 | 3. You may copy and distribute the Program (or a work based on it, 352 | under Section 2) in object code or executable form under the terms of 353 | Sections 1 and 2 above provided that you also do one of the following: 354 | 355 | a) Accompany it with the complete corresponding machine-readable 356 | source code, which must be distributed under the terms of Sections 1 357 | and 2 above on a medium customarily used for software interchange; or, 358 | 359 | b) Accompany it with a written offer, valid for at least three years, 360 | to give any third party, for a charge no more than your cost of 361 | physically performing source distribution, a complete machine-readable 362 | copy of the corresponding source code, to be distributed under the 363 | terms of Sections 1 and 2 above on a medium customarily used for 364 | software interchange; or, 365 | 366 | c) Accompany it with the information you received as to the offer to 367 | distribute corresponding source code. (This alternative is allowed 368 | only for noncommercial distribution and only if you received the 369 | program in object code or executable form with such an offer, in 370 | accord with Subsection b above.) 371 | 372 | The source code for a work means the preferred form of the work for 373 | making modifications to it. For an executable work, complete source 374 | code means all the source code for all modules it contains, plus any 375 | associated interface definition files, plus the scripts used to 376 | control compilation and installation of the executable. However, as a 377 | special exception, the source code distributed need not include 378 | anything that is normally distributed (in either source or binary 379 | form) with the major components (compiler, kernel, and so on) of the 380 | operating system on which the executable runs, unless that component 381 | itself accompanies the executable. 382 | 383 | If distribution of executable or object code is made by offering 384 | access to copy from a designated place, then offering equivalent 385 | access to copy the source code from the same place counts as 386 | distribution of the source code, even though third parties are not 387 | compelled to copy the source along with the object code. 388 | 389 | 4. You may not copy, modify, sublicense, or distribute the Program 390 | except as expressly provided under this License. Any attempt otherwise 391 | to copy, modify, sublicense or distribute the Program is void, and 392 | will automatically terminate your rights under this License. However, 393 | parties who have received copies, or rights, from you under this 394 | License will not have their licenses terminated so long as such 395 | parties remain in full compliance. 396 | 397 | 5. You are not required to accept this License, since you have not 398 | signed it. However, nothing else grants you permission to modify or 399 | distribute the Program or its derivative works. These actions are 400 | prohibited by law if you do not accept this License. Therefore, by 401 | modifying or distributing the Program (or any work based on the 402 | Program), you indicate your acceptance of this License to do so, and 403 | all its terms and conditions for copying, distributing or modifying 404 | the Program or works based on it. 405 | 406 | 6. Each time you redistribute the Program (or any work based on the 407 | Program), the recipient automatically receives a license from the 408 | original licensor to copy, distribute or modify the Program subject to 409 | these terms and conditions. You may not impose any further 410 | restrictions on the recipients' exercise of the rights granted 411 | herein. You are not responsible for enforcing compliance by third 412 | parties to this License. 413 | 414 | 7. If, as a consequence of a court judgment or allegation of patent 415 | infringement or for any other reason (not limited to patent issues), 416 | conditions are imposed on you (whether by court order, agreement or 417 | otherwise) that contradict the conditions of this License, they do not 418 | excuse you from the conditions of this License. If you cannot 419 | distribute so as to satisfy simultaneously your obligations under this 420 | License and any other pertinent obligations, then as a consequence you 421 | may not distribute the Program at all. For example, if a patent 422 | license would not permit royalty-free redistribution of the Program by 423 | all those who receive copies directly or indirectly through you, then 424 | the only way you could satisfy both it and this License would be to 425 | refrain entirely from distribution of the Program. 426 | 427 | If any portion of this section is held invalid or unenforceable under 428 | any particular circumstance, the balance of the section is intended to 429 | apply and the section as a whole is intended to apply in other 430 | circumstances. 431 | 432 | It is not the purpose of this section to induce you to infringe any 433 | patents or other property right claims or to contest validity of any 434 | such claims; this section has the sole purpose of protecting the 435 | integrity of the free software distribution system, which is 436 | implemented by public license practices. Many people have made 437 | generous contributions to the wide range of software distributed 438 | through that system in reliance on consistent application of that 439 | system; it is up to the author/donor to decide if he or she is willing 440 | to distribute software through any other system and a licensee cannot 441 | impose that choice. 442 | 443 | This section is intended to make thoroughly clear what is believed to 444 | be a consequence of the rest of this License. 445 | 446 | 8. If the distribution and/or use of the Program is restricted in 447 | certain countries either by patents or by copyrighted interfaces, the 448 | original copyright holder who places the Program under this License 449 | may add an explicit geographical distribution limitation excluding 450 | those countries, so that distribution is permitted only in or among 451 | countries not thus excluded. In such case, this License incorporates 452 | the limitation as if written in the body of this License. 453 | 454 | 9. The Free Software Foundation may publish revised and/or new 455 | versions of the General Public License from time to time. Such new 456 | versions will be similar in spirit to the present version, but may 457 | differ in detail to address new problems or concerns. 458 | 459 | Each version is given a distinguishing version number. If the Program 460 | specifies a version number of this License which applies to it and 461 | "any later version", you have the option of following the terms and 462 | conditions either of that version or of any later version published by 463 | the Free Software Foundation. If the Program does not specify a 464 | version number of this License, you may choose any version ever 465 | published by the Free Software Foundation. 466 | 467 | 10. If you wish to incorporate parts of the Program into other free 468 | programs whose distribution conditions are different, write to the 469 | author to ask for permission. For software which is copyrighted by the 470 | Free Software Foundation, write to the Free Software Foundation; we 471 | sometimes make exceptions for this. Our decision will be guided by the 472 | two goals of preserving the free status of all derivatives of our free 473 | software and of promoting the sharing and reuse of software generally. 474 | 475 | NO WARRANTY 476 | 477 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO 478 | WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE 479 | LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS 480 | AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF 481 | ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 482 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 483 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 484 | PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 485 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 486 | 487 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 488 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 489 | AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU 490 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 491 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 492 | PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 493 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 494 | FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF 495 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 496 | DAMAGES. 497 | 498 | END OF TERMS AND CONDITIONS 499 | How to Apply These Terms to Your New Programs 500 | 501 | If you develop a new program, and you want it to be of the greatest 502 | possible use to the public, the best way to achieve this is to make it 503 | free software which everyone can redistribute and change under these 504 | terms. 505 | 506 | To do so, attach the following notices to the program. It is safest to 507 | attach them to the start of each source file to most effectively 508 | convey the exclusion of warranty; and each file should have at least 509 | the "copyright" line and a pointer to where the full notice is found. 510 | 511 | One line to give the program's name and a brief idea of what it does. 512 | Copyright (C) 513 | 514 | This program is free software; you can redistribute it and/or modify 515 | it under the terms of the GNU General Public License as published by 516 | the Free Software Foundation; either version 2 of the License, or (at 517 | your option) any later version. 518 | 519 | This program is distributed in the hope that it will be useful, but 520 | WITHOUT ANY WARRANTY; without even the implied warranty of 521 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 522 | General Public License for more details. 523 | 524 | You should have received a copy of the GNU General Public License 525 | along with this program; if not, write to the Free Software 526 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 527 | USA 528 | 529 | Also add information on how to contact you by electronic and paper 530 | mail. 531 | 532 | If the program is interactive, make it output a short notice like this 533 | when it starts in an interactive mode: 534 | 535 | Gnomovision version 69, Copyright (C) year name of author Gnomovision 536 | comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is 537 | free software, and you are welcome to redistribute it under certain 538 | conditions; type `show c' for details. 539 | 540 | The hypothetical commands `show w' and `show c' should show the 541 | appropriate parts of the General Public License. Of course, the 542 | commands you use may be called something other than `show w' and `show 543 | c'; they could even be mouse-clicks or menu items--whatever suits your 544 | program. 545 | 546 | You should also get your employer (if you work as a programmer) or 547 | your school, if any, to sign a "copyright disclaimer" for the program, 548 | if necessary. Here is a sample; alter the names: 549 | 550 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 551 | `Gnomovision' (which makes passes at compilers) written by James 552 | Hacker. 553 | 554 | signature of Ty Coon, 1 April 1989 555 | Ty Coon, President of Vice 556 | 557 | This General Public License does not permit incorporating your program 558 | into proprietary programs. If your program is a subroutine library, 559 | you may consider it more useful to permit linking proprietary 560 | applications with the library. If this is what you want to do, use the 561 | GNU Library General Public License instead of this License. 562 | ---------------------------------------------------------------------- 563 | 564 | 565 | ---------------------------------------------------------------------- 566 | https://spdx.org/licenses/BSD-2-Clause.html 567 | ---------------------------------------------------------------------- 568 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 569 | 570 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 571 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 572 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 573 | ----------------------------------------------------------------------- 574 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TCP-INT: Lightweight In-band Network Telemetry for TCP 2 | 3 | In-band Network Telemetry (INT) provides visibility into the state of the network and can be used 4 | for monitoring and debugging. However, existing INT implementations do not make telemetry available 5 | to end-hosts. TCP-INT addresses this shortcoming by delivering network telemetry directly to the 6 | end-host TCP stack, enabling end-hosts to correlate local TCP state with the state of the network 7 | fabric. 8 | 9 | TCP-INT is implemented in the TCP header as a new TCP option with three fields: 10 | 11 | - INTval: the link utilization (or queue depth if utilization is 100%). 12 | - HopID: the ID of most congested switch (the packet’s TTL at the switch). 13 | - HopLat: the sum of latencies experienced across all hops. 14 | 15 | Each field has a corresponding echo-reply field (ecr) for the receiver to echo the telemetry back to 16 | the sender. 17 | 18 | ### TCP-INT option format 19 | 20 | ``` 21 | 0 1 2 3 22 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 23 | +---------------+---------------+-------+-------+---------------+ 24 | | Kind = 0x72 | Length = 12 |TagFreq|LinkSpd| INTval | 25 | +---------------+---------------+-------+-------+---------------+ 26 | | HopID=IP.TTL | HopLat (3B) | 27 | +---------------+-------+-------+-------------------------------+ 28 | | INTEcr |LnkSEcr| HIDEcr| HopLatEcr (2B) | 29 | ----------------+-------+-------+-------------------------------+ 30 | ``` 31 | 32 | ### Workflow 33 | - A process joins the `tcp-int` cgroup to indicate that its flows should be monitored by TCP-INT. 34 | - When a packet is sent, the TCP-INT eBPF adds a TCP-INT header option to the TCP header. 35 | - Upon receiving a packet with a TCP-INT header option, the switch updates the fields: 36 | - pkt.INTval = switch.INTval if switch.INTval > pkt.INTval 37 | - pkt.HopID = IP.TTL if switch.INTval > pkt.INTval 38 | - pkt.HopLat += latency through this switch 39 | - The eBPF receives the telemetry and (possibly) sends it to user-space for consumption. 40 | - When the ACK is sent, the eBPF sets the ecr fields to the latest INT received on the send path. 41 | 42 | 43 | ## Repo Organization 44 | 45 | The TCP-INT repository is organized as follows: 46 | ``` 47 | code: 48 | ┣ src/bpf: eBPF module 49 | ┣ src/tools: tool for loading, managing and monitoring the module 50 | ┣ tcp-int-exporter: user-space agent to export INT to gRPC server 51 | ┗ scripts: helper scripts 52 | ``` 53 | 54 | ### Switch Code 55 | 56 | The switch-side P4 and control plane implementations are provided in a special release of Intel P4 Studio (aka Tofino SDE). To obtain access to the SDE, contact your Intel Sales Representative. Academic researchers can apply for access through the [Intel Connectivity Research Program (ICRP)](https://www.intel.com/content/www/us/en/products/network-io/programmable-ethernet-switch/connectivity-education-hub/research-program.html). 57 | 58 | 59 | ## Getting Started 60 | 61 | ### Prerequisites 62 | 63 | * Linux Kernel 5.10.x or later 64 | 65 | ### Tested on 66 | 67 | * Linux 5.11.0-17-generic and Linux 5.13.0-28-generic 68 | * Ubuntu 21.04 and Ubuntu 21.10 69 | 70 | ### Setup steps for all end-hosts (clients and servers) 71 | 72 | Examples in this README assume that you are running as the 'root' user. If not, then most commands will likely need privilege escalation using `sudo`. 73 | 74 | #### 1. Install TCP-INT Dependencies 75 | 76 | TCP-INT requires the following packages to be installed: 77 | * build-essential 78 | * clang 79 | * llvm 80 | * gcc-multilib 81 | * libelf-dev 82 | * linux-tools 83 | * pkg-config 84 | * libbpf 0.7 (See LibBPF setup below) 85 | ``` 86 | # For Debian based distributions 87 | apt install -y build-essential clang llvm gcc-multilib libelf-dev linux-tools-$(uname -r) pkg-config 88 | ``` 89 | 90 | #### 2. Download and install Libbpf 91 | 92 | More detailed installation instructions and dependencies can be found on the Libbpf Github page:
93 | https://github.com/libbpf/libbpf/tree/v0.7.0 94 | ``` 95 | wget https://github.com/libbpf/libbpf/archive/refs/tags/v0.7.0.tar.gz 96 | tar xzf v0.7.0.tar.gz -C /opt 97 | cd /opt/libbpf-0.7.0/src 98 | make 99 | LIBDIR=/lib/x86_64-linux-gnu make install 100 | ``` 101 | Note: User might need pkg-config to build libbpf. 102 | 103 | #### 3. Copy TCP-INT source to end-hosts 104 | 105 | Copy this source code repository to each end-host where you intend to use TCP-INT. For the purpose of these instructions we will assume it is extracted to `/opt/tcp-int`. 106 | 107 | #### 4. Optional: update vmlinux.h file for the current kernel version 108 | 109 | BPF programs need to hook into data structures in memory of the current running kernel, to do this they need an up-to-date header file containing information about the running kernel. 110 | 111 | * Additional packages may be required to install the bpftool application 112 | 113 | ``` 114 | cd /opt/tcp-int/include/ 115 | bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux-$(uname -r).h 116 | rm vmlinux.h 117 | ln -s vmlinux-$(uname -r).h vmlinux.h 118 | ``` 119 | 120 | #### 5. Compile and deploy TCP-INT on the end-hosts 121 | 122 | ``` 123 | # Compile and install TCP-INT 124 | cd /opt/tcp-int/src 125 | make clean && make install 126 | ``` 127 | #### 6. Verify / set-up cgroups v2 128 | 129 | TCP-INT requires cgroups v2 in order to work. 130 | * The default 'load' command will attempt to create the following cgroup directory: `/sys/fs/cgroup/cgroup.tcp-int` 131 | * The default expects /sys/fs/cgroup to already exist as a cgroup2 mount. 132 | * An alternative path can be specified when loading with the `-c` option. 133 | * For example: `tcp_int load -c /sys/fs/cgroup/unified/my-tcp-int.cgroup` 134 | 135 | ``` 136 | # Check if cgroups v2 are already mounted correctly 137 | mount -l | grep cgroup2 138 | 139 | # Example output 1: Ubuntu 21.04: Indicates that cgroups v2 is already mounted in a subdirectory of cgroup. 140 | cgroup2 on /sys/fs/cgroup/unified type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate) 141 | 142 | # Example output 2: Debian 11 (and ubuntu 21.10): Indicates that cgroups v2 is mounted at the top level cgroup directory. 143 | # In this case you can simply create the 'unified' subdirectory or define a custom tcp-int cgroup path using the -c option. 144 | cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot) 145 | ``` 146 | 147 | ## Tagging policy 148 | The TCP-INT eBPF inserts a TCP header option in outgoing packets. The switch can "tag" the packet by setting the INT fields in the header option. If the switch were to tag every packet, it could interfere with generic receive offload (GRO) in the Linux TCP stack, possibly hurting performance. To avoid this interference, the switch can tag *some* of the packets -- enough to provide fresh telemetry, without hurting performance. 149 | 150 | ### Tagging frequency 151 | Instead of tagging every packet, the switch can tag packets at a given frequency. For example, if the tagging frequency is 16, one in every 16 packets will be tagged. The switch implements this logic probabilistically, so it's possible -- but unlikely -- for two successive packets to be tagged. The packets will be tagged in *expectation* at the specified tagging frequency. 152 | 153 | To control the tagging frequency, the sender (eBPF) specifies the tagging frequency by setting the `tagfreqkey` field in the TCP header option. The switch uses `tagfreqkey` to decide whether to tag the packet. 154 | 155 | ### Default (static) tagging policy 156 | By default, the tagging policy is to tag packets at a fixed tagging frequency. This tagging frequency is configured through the switch control plane. The sender requests the default tagging frequency by setting `tagfreqkey` to `TCP_INT_TAGFREQKEY_SWITCH_DEFAULT`. 157 | 158 | ### Dynamic tagging policy 159 | Depending on network conditions and INT freshness requirements, the sender can dynamically change the tagging frequency. The current dynamic tagging policy identifies three states of a flow: 160 | 161 | - `APPLIMITED`: the application isn't calling send() fast enough, so the in-flight packets are far below the CWND. 162 | - `CONGESTED`: there's congestion in the network fabric. 163 | - `UNCONGESTED`: there's no fabric congestion and the flow isn't application limited. 164 | 165 | The thresholds for distinguishing these states, as well as the tagging frequency to use for each state, can be configured in `include/tcp_int_common.h`. The dynamic policy can be enabled through the `TCP_INT_ENABLE_DYNAMIC_TAGGING` define. 166 | 167 | ### Loading TCP-INT and running test applications 168 | 169 | #### 1. Load TCP-INT on the end-hosts 170 | 171 | This step should be run on all end-hosts each time that node is rebooted. This loads the TCP-INT BPF program. 172 | 173 | ``` 174 | # First, attempt to unload TCP-INT in case it was not left in a clean state 175 | /usr/local/lib/bpf/tcp-int/tcp_int unload 176 | 177 | # Now load the TCP-INT BPF program 178 | /usr/local/lib/bpf/tcp-int/tcp_int load 179 | ``` 180 | 181 | #### 2. Disable TCP Timestamps (optional) 182 | 183 | TCP timestamps may need to be disabled on BOTH the client and server end-hosts, depending on the current version of TCP-INT support on the switches. If this is necessary, run the following command on ALL end-host nodes: 184 | ``` 185 | # Disable TCP timestamps 186 | sysctl -w net.ipv4.tcp_timestamps=0 187 | ``` 188 | 189 | #### 3. Server-side setup 190 | 191 | The role of the server in TCP-INT test applications is to echo back the altered TCP-INT values to the client in acknowledgement (ACK) messages. 192 | 193 | ``` 194 | # Start bash session in tcp-int cgroup 195 | bash 196 | echo $$ >> /sys/fs/cgroup/cgroup.tcp-int/cgroup.procs 197 | 198 | # Start server 199 | pkill iperf3 200 | iperf3 -s -p 5001 201 | ``` 202 | 203 | #### 4. Client-side setup 204 | 205 | The role of the client is to initialise the TCP-INT TCP option and also to receive and process the echoed TCP-INT replies coming back from the server. 206 | 207 | * Setting up a test stream with TCP-INT TCP Option initialised 208 | ``` 209 | # Open a shell terminal on the client node in the tcp-int cgroup 210 | bash 211 | echo $$ >> /sys/fs/cgroup/cgroup.tcp-int/cgroup.procs 212 | 213 | # Generate a tcp stream using TCP-INT-eBPF 214 | iperf3 -c -p 5001 -w 20M -t 120 215 | ``` 216 | 217 | * Open a second console to control and observer TCP-INT 218 | ``` 219 | # Optionally disable TCP-INT echo on the client to reduce overheads 220 | /usr/local/lib/bpf/tcp-int/tcp_int ecr-disable 221 | 222 | # Start full tracing 223 | /usr/local/lib/bpf/tcp-int/tcp_int trace 224 | ``` 225 | * Alternatively, display TCP-INT histograms showing in-network link utilisation and queue depth 226 | ``` 227 | # Optionally disable TCP-INT echo on the client to reduce overheads 228 | /usr/local/lib/bpf/tcp-int/tcp_int ecr-disable 229 | 230 | # Show TCP-INT histograms 231 | watch -t -p -n 1 timeout -s SIGINT 1 "/usr/local/lib/bpf/tcp-int/tcp_int hist-int-perid | column" 232 | 233 | # The tcp_int help text lists other modes of operation 234 | /usr/local/lib/bpf/tcp-int/tcp_int help 235 | ``` 236 | 237 | ## Running applications locally with network namespaces 238 | 239 | This was tested an Ubuntu 21.10 VM with kernel `5.13.0-28-generic`. 240 | 241 | #### 1. Load TCP-INT on the host 242 | ``` 243 | sudo /usr/local/lib/bpf/tcp-int/tcp_int load 244 | ``` 245 | 246 | #### 2. Setup the network namespaces 247 | ``` 248 | ./code/scripts/namespaces.sh 249 | ``` 250 | 251 | #### 3. Start the application in the namespaces 252 | * Open a shell for the server, add it to the tcp-int cgroup, and launch iperf3 in ns1: 253 | ``` 254 | bash 255 | echo $$ | sudo tee -a /sys/fs/cgroup/cgroup.tcp-int/cgroup.procs 256 | sudo ip netns exec ns1 iperf3 -s -p 5001 257 | ``` 258 | 259 | * Open another shell for the client and start the iperf3 client in ns2: 260 | ``` 261 | bash 262 | echo $$ | sudo tee -a /sys/fs/cgroup/cgroup.tcp-int/cgroup.procs 263 | sudo ip netns exec ns2 iperf3 -c 10.0.0.1 -p 5001 -t 120 264 | ``` 265 | 266 | #### 4. Add a `tc` pedit filter to mimic the switch 267 | Modify TCP packets (except for SYN/FIN) sent from ns2 to port 5001: set the tcp-int option fields (intval=5, id=6). 268 | This `tc` filter uses hard-coded offsets that **assume TCP timestamps are enabled**. 269 | ``` 270 | sudo ip netns exec ns2 tc qdisc replace dev v2 root handle 1: htb 271 | sudo ip netns exec ns2 tc filter add dev v2 parent 1: protocol ip flower ip_proto tcp tcp_flags 0x0/0x7 dst_port 5001 action pedit munge offset 54 u8 set 5 continue 272 | sudo ip netns exec ns2 tc filter add dev v2 parent 1: protocol ip flower ip_proto tcp tcp_flags 0x0/0x7 dst_port 5001 action pedit munge offset 56 u8 set 6 continue 273 | ``` 274 | 275 | #### 5. Monitor with tcp-int trace 276 | ``` 277 | sudo /usr/local/lib/bpf/tcp-int/tcp_int trace 278 | ``` 279 | 280 | #### 6. Remove the `tc` pedit filter 281 | ``` 282 | sudo ip netns exec ns2 tc filter del dev v2 parent 1: 283 | ``` 284 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | 2 | # Changes to TCP-INT in version 0.4.0-alpha 3 | 4 | ## New features 5 | 6 | * Link speed 7 | * Available bandwidth 8 | 9 | ## Optimizations 10 | 11 | * New Version option to display currently running tcp-int version 12 | * Removed link utilzation feature 13 | 14 | # Changes to TCP-INT in version 0.3.0-alpha 15 | 16 | ## New features 17 | 18 | * Dynamic tagging policy: the eBPF specifies the tagging frequency to get timely updates without hurting performance 19 | * New header option fields: TagFreqKey and LinkSpeed 20 | * Compact encoding of Ecr fields: HopLat and IDEcr 21 | * Performance evaluation scripts that configure the system and run workloads with various parameters 22 | * Histograms of sent and received skb length 23 | * Makefile configures the number of CPUs at compile time (instead of manually editing the header file) 24 | 25 | ## Optimizations 26 | 27 | * Removed compiler warnings 28 | * Avoid multiple eBPF map lookups by caching result 29 | 30 | ## Maintenance 31 | 32 | * Renamed "SwitchID" to "HopID" 33 | * Renamed "iratio" to "tagging frequency" 34 | 35 | ## Limitations 36 | 37 | * The new 4-bit IDEcr encoding represents at most 15 hops on the path 38 | 39 | 40 | # Changes to TCP-INT in version 0.2.0-alpha 41 | 42 | ## New features 43 | 44 | * eBPF inserts TCP-INT option header into TCP packets being sent 45 | * eBPF parses TCP-INT option header from received packets, and sends metrics to user-space for consumption 46 | * Only programs (PIDs) in the tcp-int cgroup will have their TCP flows tagged by TCP-INT 47 | * tcp_int user-space tool loads and configures eBPF 48 | * User-space tcp_int tool prints trace of INT as it arrives 49 | * The exporter receives INT events from the eBPF module and sends them as gRPC messages to a collector server 50 | * Script and instructions for trying TCP-INT on a single server with network namespaces 51 | * Script to plot timeseries of INT from trace generated by tcp_int tool 52 | 53 | ## Limitations 54 | 55 | * Fine-grained flow filtering: currently, all TCP flows belonging to a PID in the tcp-int cgroup will be tagged. In addition, it would be useful to tag flows based on some filters (e.g., destination port, destination address, socket options). 56 | * Testing: the tests in this release only exercise the basic functionality. 57 | -------------------------------------------------------------------------------- /code/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *__pycache__ 3 | src/tools/tcp_int 4 | src/bpf/tcp_int.skel.h 5 | include/vmlinux* 6 | tcp-int-exporter/src/tcp_int_exporter/tcp_int_exporter 7 | -------------------------------------------------------------------------------- /code/include/bits.bpf.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2021-2022 Intel Corporation */ 2 | /* SPDX-License-Identifier: BSD-2-Clause */ 3 | 4 | #ifndef __BITS_BPF_H 5 | #define __BITS_BPF_H 6 | 7 | static __always_inline u64 log2(u32 v) 8 | { 9 | u32 shift, r; 10 | 11 | r = (v > 0xFFFF) << 4; 12 | v >>= r; 13 | shift = (v > 0xFF) << 3; 14 | v >>= shift; 15 | r |= shift; 16 | shift = (v > 0xF) << 2; 17 | v >>= shift; 18 | r |= shift; 19 | shift = (v > 0x3) << 1; 20 | v >>= shift; 21 | r |= shift; 22 | r |= (v >> 1); 23 | 24 | return r; 25 | } 26 | 27 | static __always_inline u64 log2l(u64 v) 28 | { 29 | u32 hi = v >> 32; 30 | 31 | if (hi) 32 | return log2(hi) + 32; 33 | else 34 | return log2(v); 35 | } 36 | 37 | #endif /* __BITS_BPF_H */ 38 | -------------------------------------------------------------------------------- /code/include/tcp_int_common.bpf.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2022 Intel Corporation */ 2 | /* SPDX-License-Identifier: GPL-2.0-only */ 3 | 4 | #ifndef __TCP_INT_COMMON_BPF_H 5 | #define __TCP_INT_COMMON_BPF_H 6 | 7 | #include 8 | #include "tcp_int_opt.h" 9 | 10 | #ifdef TCP_INT_DEBUG 11 | #define tcp_int_printk(...) bpf_printk(__VA_ARGS__) 12 | #else 13 | #define tcp_int_printk(...) 14 | #endif /* TCP_INT_DEBUG */ 15 | 16 | /* TCP INT state definition */ 17 | struct tcp_int_state { 18 | bool pending_ecr; /* Indicates pending echo request */ 19 | tcp_int_val intvalecr; /* INT value to be echoed back (network order) */ 20 | tcp_int_id idecr; /* ID to be echoed back (network order) */ 21 | __u32 qdepth; /* Queue depth in data path */ 22 | tcp_int_latecr hoplatecr; /* Sum of hop latencies on data path */ 23 | __u8 linkspeedecr; /* Link speed to be echoed back */ 24 | }; 25 | 26 | /* Attaches INT state to socket */ 27 | struct { 28 | __uint(type, BPF_MAP_TYPE_SK_STORAGE); 29 | __uint(map_flags, BPF_F_NO_PREALLOC); 30 | __type(key, int); 31 | __type(value, struct tcp_int_state); 32 | } map_tcp_int_state SEC(".maps"); 33 | 34 | static inline struct tcp_int_state *tcp_int_get_state(struct bpf_sock *sk) 35 | { 36 | if (!sk) 37 | return NULL; 38 | 39 | return bpf_sk_storage_get(&map_tcp_int_state, sk, NULL, 40 | BPF_SK_STORAGE_GET_F_CREATE); 41 | } 42 | 43 | #endif /* __TCP_INT_COMMON_BPF_H */ 44 | -------------------------------------------------------------------------------- /code/include/tcp_int_common.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2021-2022 Intel Corporation */ 2 | /* SPDX-License-Identifier: Apache-2.0 */ 3 | 4 | #ifndef __TCP_INT_COMMON_H 5 | #define __TCP_INT_COMMON_H 6 | 7 | #include 8 | 9 | #define TCP_INT_ENABLE_DYNAMIC_TAGGING 0 10 | #define TCP_INT_CONG_QDEPTH_THRESH 10000 11 | #define TCP_INT_TAGFREQKEY_SWITCH_DEFAULT 0xf 12 | #define TCP_INT_TAGFREQKEY_APPLIMITED 0 13 | #define TCP_INT_TAGFREQKEY_CONGESTED 4 14 | #define TCP_INT_TAGFREQKEY_UNCONGESTED 7 15 | 16 | #define TCP_INT_BYTES_IN_KBYTE 1024 17 | #define TCP_INT_HIST_MAX_SLOTS 256 18 | #define TCP_INT_MAX_PERID_HISTS (TCP_INT_TTL_INIT + 1) 19 | #define TCP_INT_MIN_QDEPTH_SCALED 0x80 20 | #define TCP_INT_MAX_CGROUP_PATH_LEN 128 21 | #define TCP_INT_SKBLEN_BITSHIFT 8 22 | 23 | /* HopLat is the upper 24 bits of a 32-bit unsigned that represents the sum of 24 | * hop latencies in ns. On the switch, HopLat is shifted up to perform 25 | * saturating addition, and then shifed back down before sending it to the next 26 | * hop/host. 27 | * 28 | * HopLatEcr is a 16-bit encoding (compression) of the 24-bit HopLat. If HopLat 29 | * overflows 15 bits, the tcp_int_hoplat_to_hoplatecr() macro shifts HopLat down 30 | * 8 bits and stores it in HopLatEcr with MSB set to 1, indicating that 31 | * HopLatEcr contains the shifted HopLat. 32 | * 33 | * N.B. These macros assume host order. The caller should convert the argument 34 | * to host order before using this macro. 35 | */ 36 | #define tcp_int_hoplatecr_to_ns(x) \ 37 | (((x)&0x8000) ? ((__u32)(x) << (TCP_INT_HLAT_BITSHIFT * 2)) \ 38 | : ((__u32)(x) << TCP_INT_HLAT_BITSHIFT)) 39 | #define tcp_int_hoplat_to_hoplatecr(x) \ 40 | (((x)&0xff8000) ? (((x) >> TCP_INT_HLAT_BITSHIFT) | 0x8000) : (x)) 41 | 42 | /* Id is a 8-bit field that identifies the most congested hop. On the switch, Id 43 | * is set to the packet's current TTL value. Thus, the Id decreases as the 44 | * packet traverses the hops. 45 | * 46 | * IdEcr is a 4-bit field that also identifies the congested hop, but in 47 | * ascending order, starting from 1 for the first hop. 0 indicates uninitialized 48 | * Ecr data. 49 | * 50 | * N.B. Because IdEcr is 4 bits (and 0 indicates uninitialized), it cannot be 51 | * used for paths longer than 15 hops. 52 | */ 53 | #define tcp_int_id_to_idecr(x) (TCP_INT_TTL_INIT - (x)) 54 | 55 | struct tcp_int_event { 56 | __u64 ts_us; 57 | __u32 family; 58 | __u16 sport; 59 | __u16 dport; 60 | union { 61 | __u8 saddr; 62 | __u32 saddr_v4; 63 | __u32 saddr_v6[4]; 64 | }; 65 | union { 66 | __u8 daddr; 67 | __u32 daddr_v4; 68 | __u32 daddr_v6[4]; 69 | }; 70 | __u32 snd_cwnd; 71 | __u32 srtt_us; 72 | __u32 rate_delivered; 73 | __u32 rate_interval_us; 74 | __u32 mss; 75 | __u32 lost_out; 76 | tcp_int_val intval; 77 | tcp_int_id hid; 78 | __u32 hoplat; 79 | __u32 return_hoplat; 80 | __u32 segs_out; 81 | __u64 bytes_acked; 82 | __u32 total_retrans; 83 | __u8 link_speed; 84 | } __attribute__((packed)); 85 | ; 86 | 87 | enum tcp_int_hist_type { 88 | TCP_INT_HIST_TYPE_SRTT = 0, 89 | TCP_INT_HIST_TYPE_CWND, 90 | TCP_INT_HIST_TYPE_HID, 91 | TCP_INT_HIST_TYPE_AVAILBW, 92 | TCP_INT_HIST_TYPE_QDEPTH, 93 | TCP_INT_HIST_TYPE_HLAT, 94 | TCP_INT_HIST_TYPE_RXSKBLEN, 95 | TCP_INT_HIST_TYPE_TXSKBLEN, 96 | TCP_INT_HIST_TYPE_MAX 97 | }; 98 | 99 | enum tcp_int_config_key { 100 | TCP_INT_CONFIG_KEY_GLOBAL_ENABLE = 1, 101 | TCP_INT_CONFIG_KEY_HIST_ENABLE, 102 | TCP_INT_CONFIG_KEY_TRACE_ENABLE, 103 | TCP_INT_CONFIG_KEY_ECR_DISABLE, 104 | TCP_INT_CONFIG_KEY_CGROUP_PATH 105 | }; 106 | 107 | typedef union { 108 | __u64 u64; 109 | struct { 110 | char cbuf[TCP_INT_MAX_CGROUP_PATH_LEN]; 111 | }; 112 | } tcp_int_config_value; 113 | 114 | struct tcp_int_hist { 115 | __u32 slots[TCP_INT_HIST_MAX_SLOTS]; 116 | }; 117 | 118 | struct tcp_int_hist_perid { 119 | struct tcp_int_hist hist[TCP_INT_MAX_PERID_HISTS]; 120 | }; 121 | 122 | static inline bool tcp_int_ival_is_qdepth(tcp_int_val ival) 123 | { 124 | return (ival >= TCP_INT_MIN_QDEPTH_SCALED); 125 | } 126 | 127 | static inline __u32 tcp_int_ival_to_qdepth_scaled(tcp_int_val ival) 128 | { 129 | return tcp_int_ival_is_qdepth(ival) ? (ival & TCP_INT_MIN_AVAILBW_SCALED) 130 | : 0; 131 | } 132 | 133 | static inline __u32 tcp_int_ival_to_qdepth(tcp_int_val ival) 134 | { 135 | return tcp_int_ival_to_qdepth_scaled(ival) << TCP_INT_QDEPTH_BITSHIFT; 136 | } 137 | 138 | static inline __u32 tcp_int_ival_to_avail_bw(tcp_int_val ival) 139 | { 140 | return tcp_int_ival_is_qdepth(ival) ? 0 141 | : (TCP_INT_MIN_AVAILBW_SCALED - ival); 142 | } 143 | 144 | static inline __u32 tcp_int_unmap_link_speed(__u8 mapped_link_speed) 145 | { 146 | switch (mapped_link_speed) { 147 | case 1: 148 | return 10; 149 | case 2: 150 | return 25; 151 | case 3: 152 | return 40; 153 | case 4: 154 | return 50; 155 | case 5: 156 | return 100; 157 | case 6: 158 | return 200; 159 | case 7: 160 | return 400; 161 | default: 162 | return 0; 163 | } 164 | } 165 | 166 | #endif /* __TCP_INT_COMMON_H */ 167 | -------------------------------------------------------------------------------- /code/include/tcp_int_opt.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2021 Intel Corporation */ 2 | /* SPDX-License-Identifier: Apache-2.0 */ 3 | 4 | #ifndef __TCP_INT_OPT_H 5 | #define __TCP_INT_OPT_H 6 | 7 | struct uint24 { 8 | unsigned u24 : 24; 9 | } __attribute__((packed)); 10 | 11 | /* TCP INT option definitions */ 12 | typedef __u8 tcp_int_val; 13 | typedef __u8 tcp_int_id; 14 | typedef struct uint24 tcp_int_lat; 15 | typedef __u16 tcp_int_latecr; 16 | 17 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 18 | #define be24tohl(x) (bpf_ntohl((x) << 8)) 19 | #else 20 | #define be24tohl(x) (x) 21 | #endif 22 | 23 | #define TCP_INT_UTIL_BITSHIFT 3 24 | #define TCP_INT_QDEPTH_BITSHIFT 13 25 | #define TCP_INT_HLAT_BITSHIFT 8 26 | #define TCP_INT_MIN_AVAILBW_SCALED 0x7f 27 | #define TCP_INT_MIN_QDEPTH_SCALED 0x80 28 | #define TCP_INT_TTL_INIT 64 29 | #define TCP_INT_MAX_SKBLEN 65536 30 | 31 | #endif /* __TCP_INT_OPT_H */ 32 | -------------------------------------------------------------------------------- /code/scripts/clang_style_format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Automatically reindent all .c and .h source files in this project. 7 | # Need to install clag-format before running this script "apt install clang-format" 8 | 9 | if [ -d .git ] 10 | then 11 | PROJ_ROOT=$PWD 12 | 1>&2 echo "Found .git directory. Assuming this directory is project root directory:" 13 | echo $PROJ_ROOT 14 | else 15 | 1>&2 echo "No .git directory. This command must be run from project root directory" 16 | exit 1 17 | fi 18 | 19 | for f in `find . -name '*.[ch]' | grep -v '/include/vmlinux*' | grep -v 'bpf/.*.skel.h'` 20 | do 21 | clang-format -i -style="{BasedOnStyle: llvm, IndentWidth: 4, SortIncludes: false, BreakBeforeBraces: Linux}" "$f" $* 22 | done 23 | -------------------------------------------------------------------------------- /code/scripts/collect_client_stats.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | show_usage() { 7 | 1>&2 echo "usage: `basename $0` [ extra args added to iperf command ]" 8 | } 9 | 10 | if [ $# -lt 5 ] 11 | then 12 | show_usage 13 | exit 1 14 | fi 15 | 16 | DEV=$1 17 | shift 18 | TIME=$1 19 | shift 20 | DEST_IP=$1 21 | shift 22 | DIR=$1 23 | shift 24 | TCPDUMP=$1 25 | shift 26 | 27 | ss_pid=0 28 | hist_pid=0 29 | 30 | mkdir -p $DIR 31 | 32 | cp /dev/null $DIR/ifconfig_client.log 33 | 34 | date >> $DIR/ifconfig_client.log 35 | 36 | echo "Running ifconfig" 37 | ifconfig $DEV >> $DIR/ifconfig_client.log 38 | bpftool prog show > $DIR/start_stats_client.txt 39 | 40 | echo "Start top command to run every 2 second" 41 | top -b -d 2 > $DIR/top_client.log & 42 | 43 | if [[ $TCPDUMP == tcpdump_yes ]]; then 44 | tcpdump -i $DEV -s 128 -w $DIR/results_client.pcap & 45 | fi 46 | 47 | echo "Collect ss stats" 48 | /opt/tcp-int/scripts/run_ss.sh $DEST_IP > $DIR/ss_results_client.txt & 49 | ss_pid=$! 50 | 51 | echo "Start collecting tx histograms" 52 | /usr/local/lib/bpf/tcp-int/tcp_int hist-txpktlen > $DIR/tx_hist_client.log & 53 | hist_pid=$! 54 | 55 | /opt/tcp-int/scripts/tcp-int-run numactl -N netdev:$DEV -m netdev:$DEV iperf -c $DEST_IP -p 5001 -N -i 5 -e -t $TIME -P 1 -Z dctcp $* > $DIR/iperf_client.log 56 | 57 | bpftool prog show > $DIR/end_stats_client.txt 58 | date >> $DIR/ifconfig_client.log 59 | ifconfig $DEV >> $DIR/ifconfig_client.log 60 | 61 | pkill top 62 | 63 | if [[ $TCPDUMP == tcpdump_yes ]]; then 64 | pkill tcpdump 65 | fi 66 | 67 | if [[ ${hist_pid} -ne 0 ]]; then 68 | kill -s SIGINT ${hist_pid} 69 | hist_pid=0 70 | fi 71 | 72 | if [[ ${ss_pid} -ne 0 ]]; then 73 | kill -9 ${ss_pid} 74 | ss_pid=0 75 | fi 76 | 77 | echo "Perf test finished" 78 | 79 | exit 0 80 | -------------------------------------------------------------------------------- /code/scripts/collect_server_stats.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | show_usage() { 7 | 1>&2 echo "usage: `basename $0` [ extra args added to iperf command ]" 8 | } 9 | 10 | if [ $# -lt 5 ] 11 | then 12 | show_usage 13 | exit 1 14 | fi 15 | 16 | DEV=$1 17 | shift 18 | DEST_IP=$1 19 | shift 20 | DIR=$1 21 | shift 22 | WIN_SIZE=$1 23 | shift 24 | TCPDUMP=$1 25 | shift 26 | 27 | ss_pid=0 28 | hist_pid=0 29 | 30 | mkdir -p $DIR 31 | 32 | cp /dev/null $DIR/ifconfig_server.log 33 | 34 | date >> $DIR/ifconfig_server.log 35 | echo "Running ifconfig" 36 | ifconfig $DEV >> $DIR/ifconfig_server.log 37 | bpftool prog show > $DIR/start_stats_server.txt 38 | 39 | echo "Start top command to run every 2 second" 40 | top -b -d 2 > $DIR/top_server.log & 41 | 42 | if [[ $TCPDUMP == tcpdump_yes ]]; then 43 | tcpdump -i $DEV -s 128 -w $DIR/results_server.pcap & 44 | fi 45 | 46 | echo "Collect ss stats" 47 | /opt/tcp-int/scripts/run_ss.sh $DEST_IP > $DIR/ss_results_server.txt & 48 | ss_pid=$! 49 | 50 | echo "Start collecting rx packetlen histograms" 51 | /usr/local/lib/bpf/tcp-int/tcp_int hist-rxpktlen > $DIR/rx_hist_server.log & 52 | hist_pid=$! 53 | 54 | /opt/tcp-int/scripts/tcp-int-run numactl -N netdev:$DEV -m netdev:$DEV iperf -s -w $WIN_SIZE -p 5001 -Z dctcp $* > $DIR/iperf_server.log & 55 | 56 | echo "iperf server running." 57 | echo "Press return to complete the collection of statistics." 58 | 59 | read 60 | 61 | pkill iperf 62 | date >> $DIR/ifconfig_server.log 63 | ifconfig $DEV >> $DIR/ifconfig_server.log 64 | bpftool prog show > $DIR/end_stats_server.txt 65 | pkill top 66 | 67 | if [[ $TCPDUMP == tcpdump_yes ]]; then 68 | pkill tcpdump 69 | fi 70 | 71 | if [[ ${hist_pid} -ne 0 ]]; then 72 | kill -s SIGINT ${hist_pid} 73 | hist_pid=0 74 | fi 75 | 76 | if [[ ${ss_pid} -ne 0 ]]; then 77 | kill -9 ${ss_pid} 78 | ss_pid=0 79 | fi 80 | 81 | echo "Finished perf test" 82 | exit 0 83 | -------------------------------------------------------------------------------- /code/scripts/gofmt_style_indent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Automatically reindent all go files in this project. 7 | 8 | if [ -d .git ] 9 | then 10 | PROJ_ROOT=$PWD 11 | 1>&2 echo "Found .git directory. Assuming this directory is project root directory:" 12 | echo $PROJ_ROOT 13 | else 14 | 1>&2 echo "No .git directory. This command must be run from project root directory" 15 | exit 1 16 | fi 17 | 18 | gofmt -s -w . 19 | -------------------------------------------------------------------------------- /code/scripts/namespaces.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | echo "Creating namespaces ..." 7 | sudo ip link add vbr1 type bridge 8 | 9 | # Create namespaces 10 | sudo ip netns add ns1 11 | sudo ip netns add ns2 12 | 13 | # Create virtual links 14 | sudo ip link add v1 type veth peer name v3 15 | sudo ip link add v2 type veth peer name v4 16 | 17 | # Connect bridges & namespaces using these links 18 | sudo ip link set v1 netns ns1 19 | sudo ip link set v2 netns ns2 20 | sudo ip link set v3 master vbr1 21 | sudo ip link set v4 master vbr1 22 | 23 | # Add ip addresses to bridge & bring it up 24 | sudo ip link set dev vbr1 up 25 | sudo ip addr add 10.0.0.5/24 dev vbr1 26 | 27 | sudo ip link set v3 up 28 | sudo ip link set v4 up 29 | 30 | # Setup IP and set the links up 31 | sudo ip netns exec ns1 ip addr add 10.0.0.1/24 dev v1 32 | sudo ip netns exec ns2 ip addr add 10.0.0.2/24 dev v2 33 | sudo ip netns exec ns1 ip link set lo up 34 | sudo ip netns exec ns2 ip link set lo up 35 | sudo ip netns exec ns1 ip link set v1 up 36 | sudo ip netns exec ns2 ip link set v2 up 37 | 38 | echo "" 39 | echo "Created these Linux network namespaces:" 40 | 41 | echo "" 42 | echo "+-------------------+ +-----------------------------------------+" 43 | echo "| namespace ns1 | | default namespace |" 44 | echo "| | | |" 45 | echo "| 10.0.0.1/24 | | (interface) |" 46 | echo "| v1 --------- v3 ------------- |" 47 | echo "| (interface) | | | |" 48 | echo "+-------------------+ | | |" 49 | echo " | | |" 50 | echo " | vbr1 10.0.0.5/24 |" 51 | echo "|-------------------+ | | |" 52 | echo "| namespace ns2 | | | |" 53 | echo "| | | | |" 54 | echo "| 10.0.0.2/24 | | | |" 55 | echo "| v2 --------- v4 ------------- |" 56 | echo "| (interface) | | (interface) |" 57 | echo "+-------------------+ +-----------------------------------------+" 58 | echo "" 59 | echo "To start a shell in ns1 / ns2:" 60 | echo " sudo ip netns exec ns1 bash" 61 | echo " sudo ip netns exec ns2 bash" 62 | echo "" 63 | echo "Useful tcpdump options to see packets on v1 (v2) run from inside ns1 (ns2):" 64 | echo " tcpdump -l -X -vv -i v1" 65 | echo " tcpdump -l -X -vv -i v2" 66 | 67 | # Check whether br_netfilter is loaded 68 | if lsmod | grep br_netfilter &> /dev/null ; then 69 | 1>&2 echo "Warning: the br_netfilter module is loaded, which may drop IP packets between the namespaces. For more information, see: https://unix.stackexchange.com/a/671703" 70 | 1>&2 echo "If there are routing problems, try unloading the module (may interfere with docker): rmmod br_netfilter" 71 | fi 72 | -------------------------------------------------------------------------------- /code/scripts/run_ss.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | show_usage() { 7 | 1>&2 echo "usage: `basename $0` < dest_ip >" 8 | } 9 | 10 | if [ $# -ne 1 ] 11 | then 12 | show_usage 13 | exit 1 14 | fi 15 | 16 | DEST_IP=$1 17 | 18 | while true 19 | do 20 | ss -ietnOH dst $DEST_IP 21 | done 22 | -------------------------------------------------------------------------------- /code/scripts/tcp-int-run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | echo $$ >> /sys/fs/cgroup/cgroup.tcp-int/cgroup.procs 7 | $@ 8 | -------------------------------------------------------------------------------- /code/src/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2022 Intel Corporation 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | USER_OBJ = tools/tcp_int.o 5 | USER_TARGETS = tools/tcp_int 6 | SKELETON_HEADERS = bpf/tcp_int.skel.h 7 | BPF_OBJS = $(@:.skel.h=.bpf.o) 8 | 9 | PREFIX ?= /usr/local 10 | INSTALLPATH = $(PREFIX)/lib/bpf/tcp-int 11 | LIBS = -lbpf 12 | 13 | GIT_COMPILE_TIME := $(shell date -u '+%Y-%m-%dT%H:%M:%SZ') 14 | GIT_VERSION := "$(shell git describe --abbrev=12 --tags)" 15 | GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) 16 | CC := gcc 17 | 18 | CFLAGS += -DTCP_INT_NUM_CPUS=$(shell nproc --all) 19 | 20 | export VERSION_FLAGS=-DGIT_VERSION="\"$(GIT_VERSION)\"" -DGIT_COMPILE_TIME="\"$(GIT_COMPILE_TIME)\"" -DGIT_BRANCH="\"$(GIT_BRANCH)\"" 21 | 22 | .PHONY: clean 23 | 24 | all: $(USER_TARGETS) 25 | 26 | $(USER_TARGETS): %: %.c $(wildcard ../include/*.h) $(SKELETON_HEADERS) 27 | $(CC) -Wall $(CFLAGS) $(VERSION_FLAGS) $(LDFLAGS) -I../include -I. -o $@ $< $(LIBS) 28 | 29 | $(SKELETON_HEADERS): %.skel.h: %.bpf.c $(wildcard ../include/*.h) 30 | $(eval $@_BPF_OBJ := $(@:.skel.h=.bpf.o)) 31 | clang $(CFLAGS) -I../include -g -target bpf -Wall -O3 -c $< -o $($@_BPF_OBJ) 32 | llvm-strip -g $($@_BPF_OBJ) 33 | bpftool gen skeleton $($@_BPF_OBJ) > $@ 34 | 35 | clean: 36 | rm -f $(BPF_OBJS) $(USER_OBJ) $(USER_TARGETS) 37 | 38 | install: $(USER_TARGETS) 39 | install -d $(INSTALLPATH) 40 | install $^ $(INSTALLPATH) 41 | 42 | uninstall: $(BPF_OBJS) $(OBJS) $(USER_TARGETS) 43 | rm -rf $(INSTALLPATH) 44 | -------------------------------------------------------------------------------- /code/src/bpf/tcp_int.bpf.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2021-2022 Intel Corporation */ 2 | /* SPDX-License-Identifier: GPL-2.0-only */ 3 | 4 | #include "vmlinux.h" 5 | #include 6 | #include 7 | #include "tcp_int_opt.h" 8 | #include "tcp_int_common.h" 9 | #include "tcp_int_common.bpf.h" 10 | #include "bits.bpf.h" 11 | 12 | /* TCP INT option definition */ 13 | #define TCP_INT_OPT_KIND 0x72 14 | struct tcp_int_opt { 15 | __u8 kind; 16 | __u8 len; 17 | /* XXX bit-fields are sent in reverse on the wire: */ 18 | unsigned linkspeed : 4; 19 | unsigned tagfreqkey : 4; 20 | tcp_int_val intval; 21 | tcp_int_id id; 22 | tcp_int_lat hoplat; 23 | tcp_int_val intvalecr; 24 | unsigned linkspeedecr : 4; 25 | unsigned idecr : 4; 26 | tcp_int_latecr hoplatecr; 27 | } __attribute__((packed)); 28 | 29 | /* TCP INT configuration map */ 30 | #define TCP_INT_MAP_CONFIG_MAX_ENTRIES 16 31 | struct { 32 | __uint(type, BPF_MAP_TYPE_HASH); 33 | __uint(max_entries, TCP_INT_MAP_CONFIG_MAX_ENTRIES); 34 | __type(key, __u16); 35 | __type(value, tcp_int_config_value); 36 | } map_tcp_int_config SEC(".maps"); 37 | 38 | /* Perf events to user space */ 39 | struct { 40 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); 41 | __uint(max_entries, TCP_INT_NUM_CPUS); 42 | __uint(key_size, sizeof(__u32)); 43 | __uint(value_size, sizeof(__u32)); 44 | } map_tcp_int_events SEC(".maps"); 45 | 46 | /* Histograms */ 47 | struct { 48 | __uint(type, BPF_MAP_TYPE_HASH); 49 | __uint(max_entries, TCP_INT_HIST_TYPE_MAX); 50 | __type(key, enum tcp_int_hist_type); 51 | __type(value, struct tcp_int_hist); 52 | } map_tcp_int_hists SEC(".maps"); 53 | 54 | /* Per hop-ID histograms */ 55 | struct { 56 | __uint(type, BPF_MAP_TYPE_HASH); 57 | __uint(max_entries, TCP_INT_MAX_PERID_HISTS); 58 | __type(key, enum tcp_int_hist_type); 59 | __type(value, struct tcp_int_hist_perid); 60 | } map_tcp_int_hists_perid SEC(".maps"); 61 | 62 | static inline void tcp_int_enable_tcp_opt_cb(struct bpf_sock_ops *skops) 63 | { 64 | int cb_flags; 65 | 66 | cb_flags = skops->bpf_sock_ops_cb_flags | 67 | BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG | 68 | BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG; 69 | bpf_sock_ops_cb_flags_set(skops, cb_flags); 70 | } 71 | 72 | static inline void tcp_int_reserve_hdr_opt(struct bpf_sock_ops *skops, 73 | __u32 size) 74 | { 75 | bpf_reserve_hdr_opt(skops, size, 0); 76 | } 77 | 78 | static inline int tcp_int_is_mode_hist(void) 79 | { 80 | int key = TCP_INT_CONFIG_KEY_HIST_ENABLE; 81 | tcp_int_config_value *ptr_enabled; 82 | 83 | ptr_enabled = bpf_map_lookup_elem(&map_tcp_int_config, &key); 84 | if (ptr_enabled) 85 | return ptr_enabled->u64; 86 | return 0; 87 | } 88 | 89 | static inline void tcp_int_update_hist(enum tcp_int_hist_type type, 90 | tcp_int_id hid, __u64 val, bool linear) 91 | { 92 | struct tcp_int_hist_perid *hist_perid_ptr; 93 | struct tcp_int_hist *hist_ptr; 94 | __u64 slot; 95 | 96 | hist_perid_ptr = bpf_map_lookup_elem(&map_tcp_int_hists_perid, &type); 97 | hist_ptr = bpf_map_lookup_elem(&map_tcp_int_hists, &type); 98 | if (!hist_perid_ptr || !hist_ptr) { 99 | return; 100 | } 101 | 102 | if (hid >= TCP_INT_MAX_PERID_HISTS) { 103 | hid = TCP_INT_MAX_PERID_HISTS - 1; 104 | } 105 | 106 | slot = linear ? val : log2l(val); 107 | if (slot >= TCP_INT_HIST_MAX_SLOTS) { 108 | slot = TCP_INT_HIST_MAX_SLOTS - 1; 109 | } 110 | __sync_fetch_and_add(&(hist_perid_ptr->hist[hid].slots[slot]), 1); 111 | __sync_fetch_and_add(&hist_ptr->slots[slot], 1); 112 | } 113 | 114 | static inline void tcp_int_add_tcpopt(struct bpf_sock_ops *skops, 115 | struct tcp_int_state *istate) 116 | { 117 | struct tcp_int_opt iopt = {0}; 118 | __u64 val; 119 | 120 | iopt.kind = TCP_INT_OPT_KIND; 121 | iopt.len = sizeof(iopt); 122 | iopt.intvalecr = istate->intvalecr; 123 | iopt.idecr = istate->idecr; 124 | iopt.hoplatecr = istate->hoplatecr; 125 | iopt.linkspeedecr = istate->linkspeedecr; 126 | 127 | #if TCP_INT_ENABLE_DYNAMIC_TAGGING 128 | if (skops->packets_out < 1) 129 | iopt.tagfreqkey = TCP_INT_TAGFREQKEY_APPLIMITED; 130 | else if (istate->qdepth > TCP_INT_CONG_QDEPTH_THRESH) 131 | iopt.tagfreqkey = TCP_INT_TAGFREQKEY_CONGESTED; 132 | else 133 | iopt.tagfreqkey = TCP_INT_TAGFREQKEY_UNCONGESTED; 134 | #else 135 | iopt.tagfreqkey = TCP_INT_TAGFREQKEY_SWITCH_DEFAULT; 136 | #endif // TCP_INT_ENABLE_DYNAMIC_TAGGING 137 | 138 | bpf_store_hdr_opt(skops, &iopt, sizeof(iopt), 0); 139 | 140 | if (tcp_int_is_mode_hist()) { 141 | val = skops->skb_len >> TCP_INT_SKBLEN_BITSHIFT; 142 | tcp_int_update_hist(TCP_INT_HIST_TYPE_TXSKBLEN, iopt.idecr, val, true); 143 | } 144 | } 145 | 146 | static void tcp_int_update_hists(struct bpf_sock_ops *skops, 147 | struct tcp_int_opt *iopt) 148 | { 149 | enum tcp_int_hist_type type; 150 | bool linear; 151 | __u64 val; 152 | 153 | for (type = 0; type < TCP_INT_HIST_TYPE_MAX; type++) { 154 | switch (type) { 155 | case TCP_INT_HIST_TYPE_SRTT: 156 | val = skops->srtt_us >> 3; 157 | linear = false; 158 | break; 159 | case TCP_INT_HIST_TYPE_CWND: 160 | val = skops->snd_cwnd; 161 | linear = false; 162 | break; 163 | case TCP_INT_HIST_TYPE_AVAILBW: 164 | val = tcp_int_ival_to_avail_bw(iopt->intvalecr); 165 | linear = true; 166 | break; 167 | case TCP_INT_HIST_TYPE_QDEPTH: 168 | val = tcp_int_ival_to_qdepth(iopt->intvalecr) / 169 | TCP_INT_BYTES_IN_KBYTE; 170 | linear = false; 171 | break; 172 | case TCP_INT_HIST_TYPE_HID: 173 | val = iopt->idecr; 174 | linear = true; 175 | break; 176 | case TCP_INT_HIST_TYPE_HLAT: 177 | val = tcp_int_hoplatecr_to_ns(iopt->hoplatecr); 178 | linear = false; 179 | break; 180 | case TCP_INT_HIST_TYPE_RXSKBLEN: 181 | val = skops->skb_len >> TCP_INT_SKBLEN_BITSHIFT; 182 | linear = true; 183 | break; 184 | default: 185 | continue; 186 | } 187 | tcp_int_update_hist(type, iopt->idecr, val, linear); 188 | } 189 | } 190 | 191 | static void tcp_int_send_event(struct bpf_sock_ops *skops, 192 | struct tcp_int_opt *iopt) 193 | { 194 | struct tcp_int_event event = {0}; 195 | 196 | event.ts_us = bpf_ktime_get_ns() / 1000; 197 | event.dport = bpf_ntohl(skops->remote_port); 198 | event.sport = skops->local_port; 199 | event.family = skops->family; 200 | event.saddr_v4 = skops->local_ip4; 201 | event.daddr_v4 = skops->remote_ip4; 202 | /* TODO add ipv6 support */ 203 | event.snd_cwnd = skops->snd_cwnd; 204 | event.srtt_us = skops->srtt_us; 205 | event.rate_delivered = skops->rate_delivered; 206 | event.rate_interval_us = skops->rate_interval_us; 207 | event.mss = skops->mss_cache; 208 | event.lost_out = skops->lost_out; 209 | event.intval = iopt->intvalecr; 210 | event.hid = iopt->idecr; 211 | event.hoplat = iopt->hoplatecr; 212 | event.return_hoplat = be24tohl(iopt->hoplat.u24); 213 | event.segs_out = skops->segs_out; 214 | event.bytes_acked = skops->bytes_acked; 215 | event.total_retrans = skops->total_retrans; 216 | event.link_speed = iopt->linkspeedecr; 217 | bpf_perf_event_output(skops, &map_tcp_int_events, BPF_F_CURRENT_CPU, &event, 218 | sizeof(event)); 219 | } 220 | 221 | static inline int tcp_int_is_ecr_enabled(void) 222 | { 223 | int key = TCP_INT_CONFIG_KEY_ECR_DISABLE; 224 | tcp_int_config_value *ptr_enabled; 225 | 226 | ptr_enabled = bpf_map_lookup_elem(&map_tcp_int_config, &key); 227 | if (ptr_enabled) 228 | return !(ptr_enabled->u64); 229 | return 1; 230 | } 231 | 232 | static inline int tcp_int_is_mode_trace(void) 233 | { 234 | int key = TCP_INT_CONFIG_KEY_TRACE_ENABLE; 235 | tcp_int_config_value *ptr_enabled; 236 | 237 | ptr_enabled = bpf_map_lookup_elem(&map_tcp_int_config, &key); 238 | if (ptr_enabled) 239 | return ptr_enabled->u64; 240 | return 0; 241 | } 242 | 243 | static inline int tcp_int_is_enabled(void) 244 | { 245 | int key = TCP_INT_CONFIG_KEY_GLOBAL_ENABLE; 246 | tcp_int_config_value *ptr_enabled; 247 | 248 | ptr_enabled = bpf_map_lookup_elem(&map_tcp_int_config, &key); 249 | if (ptr_enabled) 250 | return ptr_enabled->u64; 251 | return 0; 252 | } 253 | 254 | static inline void tcp_int_process_tcpopt(struct bpf_sock_ops *skops, 255 | struct tcp_int_state *istate) 256 | { 257 | struct tcp_int_opt iopt = {}; 258 | bool _tcp_int_is_enabled; /* Optimization: cache tcp_int_is_enabled() */ 259 | int rv; 260 | 261 | iopt.kind = TCP_INT_OPT_KIND; 262 | 263 | rv = bpf_load_hdr_opt(skops, &iopt, sizeof(iopt), 0); 264 | if (rv != sizeof(iopt)) { 265 | return; 266 | } 267 | 268 | /* Request echo only if there is an update */ 269 | if (iopt.id) { 270 | istate->intvalecr = iopt.intval; 271 | istate->idecr = tcp_int_id_to_idecr(iopt.id); 272 | istate->hoplatecr = 273 | tcp_int_hoplat_to_hoplatecr(be24tohl(iopt.hoplat.u24)); 274 | istate->linkspeedecr = iopt.linkspeed; 275 | istate->pending_ecr = true; 276 | } 277 | 278 | /* Ignore local events with no updates */ 279 | if (iopt.idecr == 0) { 280 | return; 281 | } 282 | 283 | /* qdepth = qdepth_old * 7/8 + qdepth_new * 1/7 */ 284 | istate->qdepth -= (istate->qdepth >> 3); 285 | istate->qdepth = 286 | istate->qdepth + (tcp_int_ival_to_qdepth(iopt.intvalecr) >> 3); 287 | 288 | _tcp_int_is_enabled = tcp_int_is_enabled(); 289 | if (_tcp_int_is_enabled && tcp_int_is_mode_hist()) { 290 | tcp_int_update_hists(skops, &iopt); 291 | } 292 | if (_tcp_int_is_enabled && tcp_int_is_mode_trace()) { 293 | tcp_int_send_event(skops, &iopt); 294 | } 295 | } 296 | 297 | SEC("sockops") 298 | int tcp_int(struct bpf_sock_ops *skops) 299 | { 300 | struct tcp_int_state *istate; 301 | 302 | istate = tcp_int_get_state(skops->sk); 303 | if (!istate) 304 | return 1; 305 | 306 | switch (skops->op) { 307 | case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: 308 | case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: 309 | tcp_int_enable_tcp_opt_cb(skops); 310 | break; 311 | case BPF_SOCK_OPS_HDR_OPT_LEN_CB: 312 | if (tcp_int_is_enabled() || 313 | (tcp_int_is_ecr_enabled() && istate->pending_ecr)) { 314 | tcp_int_reserve_hdr_opt(skops, sizeof(struct tcp_int_opt)); 315 | } 316 | break; 317 | case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: 318 | if (tcp_int_is_enabled() || 319 | (tcp_int_is_ecr_enabled() && istate->pending_ecr)) { 320 | tcp_int_add_tcpopt(skops, istate); 321 | istate->pending_ecr = false; 322 | } 323 | break; 324 | case BPF_SOCK_OPS_PARSE_HDR_OPT_CB: 325 | tcp_int_process_tcpopt(skops, istate); 326 | break; 327 | default: 328 | break; 329 | } 330 | 331 | return 1; 332 | } 333 | 334 | char _license[] SEC("license") = "GPL"; 335 | -------------------------------------------------------------------------------- /code/src/tools/tcp_int.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2021-2022 Intel Corporation */ 2 | /* SPDX-License-Identifier: Apache-2.0 */ 3 | 4 | /* Copyright (c) 2020 Wenbo Zhang */ 5 | /* https://github.com/iovisor/bcc/blob/master/libbpf-tools/trace_helpers.c */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "tcp_int.h" 16 | #include "tcp_int_common.h" 17 | #include "bpf/tcp_int.skel.h" 18 | 19 | static volatile sig_atomic_t tcp_int_exiting = 0; 20 | 21 | static const char *tcp_int_doc = 22 | "Trace TCP congestion.\n" 23 | "\n" 24 | "USAGE: tcp_int [load,run,unload,help] [-d]\n" 25 | "\n" 26 | "EXAMPLES:\n" 27 | " tcp_int load # Loads tcp_int and " 28 | "related BPF programs with the default cgroup path\n" 29 | " tcp_int load -c {path} # Loads tcp_int and " 30 | "related BPF programs with a custom cgroup2 mountpoint\n" 31 | " tcp_int enable # Enables tcp-int " 32 | "option handling\n" 33 | " tcp_int trace # Enables tcp-int and " 34 | "starts tracing\n" 35 | " tcp_int hist # Enables tcp-int and " 36 | "start histograming (all histograms)\n" 37 | " tcp_int hist-int # Enables tcp-int and " 38 | "start histograming (INT-related histograms)\n" 39 | " tcp_int hist-int-perid # Enables tcp-int and " 40 | "start histograming (INT-related histograms per hop ID)\n" 41 | " tcp_int hist-[rtt,cwnd,qdepth,util,availbw,\n" 42 | " hoplat,hid,rxskblen,txskblen] # Enables tcp-int and " 43 | "start histograming (selected histogram)\n" 44 | " tcp_int ecr-enable # Enables echo replies " 45 | "(default = enabled)\n" 46 | " tcp_int ecr-disable # Disables echo " 47 | "replies\n" 48 | " tcp_int events-enable # Enables perf events " 49 | "(default = disabled)\n" 50 | " tcp_int events-disable # Disables perf " 51 | "events\n" 52 | " tcp_int disable # Disables tcp-int " 53 | "option handling\n" 54 | " tcp_int unload # Unloads all tcp_int " 55 | "BPF programs\n" 56 | " tcp_int unload -d # Unloads all tcp_int " 57 | "BPF programs with debug enabled\n" 58 | " tcp_int version # Prints compile time, " 59 | "version and current branch name" 60 | " tcp_int help # Prints help " 61 | "message\n"; 62 | 63 | enum tcp_int_object_type { 64 | TCP_INT_OBJECT_SOCKOPS = 0, 65 | TCP_INT_OBJECT_MAP_STATE, 66 | TCP_INT_OBJECT_MAP_CONFIG, 67 | TCP_INT_OBJECT_MAP_EVENTS, 68 | TCP_INT_OBJECT_MAP_HISTS, 69 | TCP_INT_OBJECT_MAP_HISTS_PERID, 70 | TCP_INT_OBJECT_LINK_CGROUP, 71 | TCP_INT_OBJECT_MAX 72 | }; 73 | 74 | static const char tcp_int_bpf_object_paths[][50] = { 75 | [TCP_INT_OBJECT_SOCKOPS] = TCP_INT_BPF_PIN_PATH "/sockops", 76 | [TCP_INT_OBJECT_MAP_STATE] = TCP_INT_BPF_PIN_PATH "/map_tcp_int_state", 77 | [TCP_INT_OBJECT_MAP_CONFIG] = TCP_INT_BPF_PIN_PATH "/map_tcp_int_config", 78 | [TCP_INT_OBJECT_MAP_EVENTS] = TCP_INT_BPF_PIN_PATH "/map_tcp_int_events", 79 | [TCP_INT_OBJECT_MAP_HISTS] = TCP_INT_BPF_PIN_PATH "/map_tcp_int_hists", 80 | [TCP_INT_OBJECT_MAP_HISTS_PERID] = 81 | TCP_INT_BPF_PIN_PATH "/map_tcp_int_hists_perid", 82 | [TCP_INT_OBJECT_LINK_CGROUP] = TCP_INT_BPF_PIN_PATH "/link_cgroup", 83 | }; 84 | 85 | static const tcp_int_config_value TCP_INT_CONFIG_FALSE = {0}; 86 | static const tcp_int_config_value TCP_INT_CONFIG_TRUE = {1}; 87 | 88 | static void show_help(void) { fprintf(stdout, "%s", tcp_int_doc); } 89 | 90 | #define min(x, y) \ 91 | ({ \ 92 | typeof(x) _min1 = (x); \ 93 | typeof(y) _min2 = (y); \ 94 | (void)(&_min1 == &_min2); \ 95 | _min1 < _min2 ? _min1 : _min2; \ 96 | }) 97 | 98 | static const char *validate_cgroup_path(const char *path) 99 | { 100 | 101 | if (strlen(path) >= TCP_INT_MAX_CGROUP_PATH_LEN) { 102 | fprintf(stderr, "Cgroup path length is too long (max %d characters)\n", 103 | TCP_INT_MAX_CGROUP_PATH_LEN - 1); 104 | return NULL; 105 | } 106 | 107 | if (strncmp(path, TCP_INT_CGROUP_BASE_PATH, 108 | strlen(TCP_INT_CGROUP_BASE_PATH)) != 0) { 109 | fprintf(stderr, 110 | "Cgroup must be specified as an absolute path beginning with " 111 | "'%s'\n", 112 | TCP_INT_CGROUP_BASE_PATH); 113 | return NULL; 114 | } 115 | 116 | return path; 117 | } 118 | 119 | static void print_stars(unsigned int val, unsigned int val_max, int width) 120 | { 121 | int num_stars, num_spaces, i; 122 | bool need_plus; 123 | 124 | if (!val_max) { 125 | return; 126 | } 127 | 128 | num_stars = min(val, val_max) * width / val_max; 129 | num_spaces = width - num_stars; 130 | need_plus = val > val_max; 131 | 132 | for (i = 0; i < num_stars; i++) 133 | printf("*"); 134 | for (i = 0; i < num_spaces; i++) 135 | printf(" "); 136 | if (need_plus) 137 | printf("+"); 138 | } 139 | 140 | void print_linear_hist(unsigned int *vals, int vals_size, float base, 141 | float step, int idx_min, int idx_max, 142 | const char *val_type, bool norange) 143 | { 144 | unsigned int val_max = 0; 145 | int i, j, stars_max = 40; 146 | unsigned int val = 0; 147 | bool fixed_max; 148 | 149 | fixed_max = (idx_max != -1); 150 | 151 | for (i = 0; i < vals_size; i++) { 152 | val = (fixed_max && (i > idx_max)) ? (val + vals[i]) : vals[i]; 153 | if (val > 0) { 154 | if (!fixed_max && (idx_max < i)) { 155 | idx_max = i; 156 | } 157 | if (idx_min < 0) 158 | idx_min = i; 159 | } 160 | if (val > val_max) 161 | val_max = val; 162 | } 163 | 164 | if ((val_max == 0) || idx_max < 0) 165 | return; 166 | 167 | printf(" %-19s : count distribution\n", val_type); 168 | for (i = idx_min; i <= idx_max; i++) { 169 | val = vals[i]; 170 | if (fixed_max && i == idx_max) { 171 | for (j = i + 1; j < vals_size; j++) { 172 | val += vals[j]; 173 | } 174 | } 175 | if (norange) { 176 | printf("%10.0f %-13s : %-8d |", base + i * step, "", val); 177 | } else if (fixed_max && i == idx_max) { 178 | printf("%10.1f -> %-10s : %-8d |", base + i * step, "INF", val); 179 | } else { 180 | printf("%10.1f -> %-10.1f : %-8d |", base + i * step, 181 | base + (i + 1) * step, val); 182 | } 183 | print_stars(val, val_max, stars_max); 184 | printf("|\n"); 185 | } 186 | } 187 | 188 | void print_log2_hist(unsigned int *vals, int vals_size, int idx_max, 189 | const char *val_type) 190 | { 191 | unsigned long long low, high; 192 | unsigned int val_max = 0; 193 | int stars, width, i, j; 194 | unsigned int val = 0; 195 | int stars_max = 40; 196 | bool fixed_max; 197 | 198 | fixed_max = (idx_max != -1); 199 | 200 | for (i = 0; i < vals_size; i++) { 201 | val = (fixed_max && (i > idx_max)) ? (val + vals[i]) : vals[i]; 202 | if (val > 0) 203 | if (!fixed_max && (idx_max < i)) { 204 | idx_max = i; 205 | } 206 | if (val > val_max) 207 | val_max = val; 208 | } 209 | 210 | if ((val_max == 0) || idx_max < 0) 211 | return; 212 | 213 | printf("%*s%-*s : count distribution\n", idx_max <= 32 ? 5 : 15, "", 214 | idx_max <= 32 ? 19 : 29, val_type); 215 | 216 | if (idx_max <= 32) 217 | stars = stars_max; 218 | else 219 | stars = stars_max / 2; 220 | 221 | for (i = 0; i <= idx_max; i++) { 222 | low = (1ULL << (i + 1)) >> 1; 223 | high = (1ULL << (i + 1)) - 1; 224 | if (low == high) 225 | low -= 1; 226 | val = vals[i]; 227 | if (fixed_max && i == idx_max) { 228 | for (j = i + 1; j < vals_size; j++) { 229 | val += vals[j]; 230 | } 231 | } 232 | width = idx_max <= 32 ? 10 : 20; 233 | if (fixed_max && i == idx_max) { 234 | printf("%*lld -> %-*s : %-8d |", width, low, width, "INF", val); 235 | } else { 236 | printf("%*lld -> %-*lld : %-8d |", width, low, width, high, val); 237 | } 238 | print_stars(val, val_max, stars); 239 | printf("|\n"); 240 | } 241 | } 242 | 243 | static bool tcp_int_obj_is_loaded(enum tcp_int_object_type type) 244 | { 245 | int fd; 246 | fd = bpf_obj_get(tcp_int_bpf_object_paths[type]); 247 | if (fd < 0) { 248 | return false; 249 | } else { 250 | close(fd); 251 | return true; 252 | } 253 | } 254 | 255 | static struct bpf_link *tcp_int_get_link(enum tcp_int_object_type type) 256 | { 257 | struct bpf_link *link; 258 | int err; 259 | 260 | link = bpf_link__open(tcp_int_bpf_object_paths[type]); 261 | err = libbpf_get_error(link); 262 | if (err) { 263 | fprintf(stderr, 264 | "Failed to get a link to the BPF object - %d. Verify it is " 265 | "loaded\n", 266 | err); 267 | return NULL; 268 | } 269 | 270 | return link; 271 | } 272 | 273 | static int tcp_int_get_fd(enum tcp_int_object_type type) 274 | { 275 | int fd; 276 | 277 | fd = bpf_obj_get(tcp_int_bpf_object_paths[type]); 278 | if (fd < 0) { 279 | fprintf( 280 | stderr, 281 | "Failed to get an fd to the BPF object - %d. Verify it is loaded\n", 282 | fd); 283 | return -1; 284 | } 285 | 286 | return fd; 287 | } 288 | 289 | static int tcp_int_get_cgroup_fd(const char *path_val) 290 | { 291 | int fd; 292 | 293 | if (mkdir(path_val, 0777) && errno != EEXIST) { 294 | fprintf(stderr, "Failed to create cgroup %s - %s.\n", path_val, 295 | strerror(errno)); 296 | return -1; 297 | } 298 | 299 | fd = openat(0, path_val, O_RDONLY); 300 | if (fd < 0) { 301 | fprintf(stderr, "Failed to open cgroup %s - %d.\n", path_val, fd); 302 | return -1; 303 | } 304 | 305 | return fd; 306 | } 307 | 308 | static int tcp_int_attach_cgroup(struct tcp_int_bpf *tcp_in_obj, 309 | const char *path_val) 310 | { 311 | struct bpf_link *cgroup_link; 312 | int err = TCP_INT_ERR_SYS; 313 | int cgroup_map_fd = -1; 314 | 315 | cgroup_map_fd = tcp_int_get_cgroup_fd(path_val); 316 | if (cgroup_map_fd == -1) { 317 | goto err; 318 | } 319 | 320 | cgroup_link = 321 | bpf_program__attach_cgroup(tcp_in_obj->progs.tcp_int, cgroup_map_fd); 322 | err = libbpf_get_error(cgroup_link); 323 | if (err) { 324 | fprintf(stderr, "Failed to attach to cgroup - %d.\n", err); 325 | goto err; 326 | } 327 | 328 | err = bpf_link__pin(cgroup_link, 329 | tcp_int_bpf_object_paths[TCP_INT_OBJECT_LINK_CGROUP]); 330 | if (err < 0) { 331 | fprintf(stderr, "Failed to pin cgroup link - %d.\n", err); 332 | goto err; 333 | } 334 | 335 | err: 336 | if (cgroup_map_fd != -1) { 337 | close(cgroup_map_fd); 338 | } 339 | 340 | return err; 341 | } 342 | 343 | static int tcp_int_set_config(__u16 cfg_key, tcp_int_config_value cfg_val) 344 | { 345 | int err = TCP_INT_OK; 346 | int cfg_map; 347 | 348 | cfg_map = tcp_int_get_fd(TCP_INT_OBJECT_MAP_CONFIG); 349 | if (cfg_map < 0) { 350 | return TCP_INT_ERR_BPF; 351 | } 352 | 353 | err = bpf_map_update_elem(cfg_map, &cfg_key, &cfg_val, BPF_ANY); 354 | if (err < 0) { 355 | fprintf(stderr, "Failed to update TCP INT config. err code: %i\n", err); 356 | return TCP_INT_ERR_BPF; 357 | } 358 | 359 | return err; 360 | } 361 | 362 | static int tcp_int_get_config(__u16 cfg_key, tcp_int_config_value *ret_val) 363 | { 364 | int err = TCP_INT_OK; 365 | int cfg_map; 366 | 367 | cfg_map = tcp_int_get_fd(TCP_INT_OBJECT_MAP_CONFIG); 368 | if (cfg_map < 0) { 369 | return -1; 370 | } 371 | 372 | err = bpf_map_lookup_elem(cfg_map, &cfg_key, ret_val); 373 | if (err < 0) { 374 | fprintf(stderr, 375 | "Failed to retrieve TCP-INT config state. err code: %i\n", err); 376 | return -1; 377 | } 378 | 379 | return err; 380 | } 381 | 382 | static int tcp_int_get_cgroup_path(char *path_buf) 383 | { 384 | tcp_int_config_value cbuf_cfg_val; 385 | int err = TCP_INT_OK; 386 | 387 | err = tcp_int_get_config(TCP_INT_CONFIG_KEY_CGROUP_PATH, &cbuf_cfg_val); 388 | if (err) { 389 | return -1; 390 | } 391 | strncpy(path_buf, cbuf_cfg_val.cbuf, TCP_INT_MAX_CGROUP_PATH_LEN); 392 | 393 | return err; 394 | } 395 | 396 | static int tcp_int_set_cgroup_path(const char *path_val) 397 | { 398 | tcp_int_config_value cbuf_cfg_val; 399 | int err = TCP_INT_OK; 400 | 401 | strncpy(cbuf_cfg_val.cbuf, path_val, TCP_INT_MAX_CGROUP_PATH_LEN - 1); 402 | err = tcp_int_set_config(TCP_INT_CONFIG_KEY_CGROUP_PATH, cbuf_cfg_val); 403 | 404 | return err; 405 | } 406 | 407 | static int tcp_int_remove_mountpoint(const char *mountpoint) 408 | { 409 | int err; 410 | err = rmdir(mountpoint); 411 | 412 | /* Don't print a warning if mountpoint does not exist */ 413 | if (err && errno != ENOENT) { 414 | fprintf(stderr, 415 | "Warning: Could not remove mountpoint %s. rmdir error: %s.\n", 416 | mountpoint, strerror(err)); 417 | } 418 | return TCP_INT_OK; 419 | } 420 | 421 | static int tcp_int_bpf_detach_and_close(void) 422 | { 423 | struct bpf_link *link; 424 | int destroy_count = 0; 425 | int err = TCP_INT_OK; 426 | int i; 427 | 428 | for (i = 0; i < TCP_INT_OBJECT_MAX; i++) { 429 | 430 | if (tcp_int_obj_is_loaded(i)) { 431 | link = tcp_int_get_link(i); 432 | if (!link) { 433 | err = TCP_INT_ERR_BPF; 434 | continue; 435 | } 436 | 437 | bpf_link__unpin(link); 438 | bpf_link__destroy(link); 439 | destroy_count++; 440 | } 441 | } 442 | 443 | if (err) 444 | fprintf(stderr, "Error unloading one or more TCP-INT BPF objects.\n" 445 | "Verify it was loaded.\n"); 446 | 447 | if (destroy_count == 0) { 448 | fprintf( 449 | stderr, 450 | "No TCP-INT BPF objects removed. Program was likely not loaded.\n"); 451 | } 452 | 453 | return err; 454 | } 455 | 456 | static int tcp_int_unload(void) 457 | { 458 | char cg_mountpoint[TCP_INT_MAX_CGROUP_PATH_LEN]; 459 | int cg_err = TCP_INT_OK; 460 | int err = TCP_INT_OK; 461 | 462 | tcp_int_set_config(TCP_INT_CONFIG_KEY_GLOBAL_ENABLE, TCP_INT_CONFIG_FALSE); 463 | cg_err = tcp_int_get_cgroup_path(cg_mountpoint); 464 | err = tcp_int_bpf_detach_and_close(); 465 | tcp_int_remove_mountpoint(TCP_INT_BPF_PIN_PATH); 466 | if (!cg_err) { 467 | tcp_int_remove_mountpoint(cg_mountpoint); 468 | } 469 | 470 | return err; 471 | } 472 | 473 | static void tcp_int_version(void) 474 | { 475 | printf("Compile time: %s\n", GIT_COMPILE_TIME); 476 | printf("Version: %s\n", GIT_VERSION); 477 | printf("Branch: %s\n", GIT_BRANCH); 478 | } 479 | 480 | static int tcp_int_load(const char *cg_path) 481 | { 482 | struct tcp_int_bpf *tcp_int_obj; 483 | bool pinned = false; 484 | int err; 485 | 486 | tcp_int_obj = tcp_int_bpf__open_and_load(); 487 | if (!tcp_int_obj) { 488 | fprintf(stderr, "Failed to open and/or load main TCP-INT BPF object\n"); 489 | return TCP_INT_ERR_BPF; 490 | } 491 | 492 | err = tcp_int_bpf__attach(tcp_int_obj); 493 | if (err) { 494 | fprintf(stderr, "Failed to attach main TCP-INT BPF object- %s\n", 495 | strerror(err)); 496 | goto err; 497 | } 498 | 499 | err = bpf_object__pin(tcp_int_obj->obj, TCP_INT_BPF_PIN_PATH); 500 | if (err) { 501 | fprintf(stderr, "Failed to pin main TCP-INT BPF object- %s\n", 502 | strerror(err)); 503 | goto err; 504 | } 505 | pinned = true; 506 | 507 | err = tcp_int_set_cgroup_path(cg_path); 508 | if (err) { 509 | fprintf(stderr, "Failed to store cgroup path in BPF map\n"); 510 | goto err; 511 | } 512 | 513 | err = tcp_int_attach_cgroup(tcp_int_obj, cg_path); 514 | if (err) { 515 | fprintf(stderr, "Failed to attach cgroup- %s\n", strerror(err)); 516 | goto err; 517 | } 518 | 519 | /* Set default config in eBPF map */ 520 | err = tcp_int_set_config(TCP_INT_CONFIG_KEY_TRACE_ENABLE, 521 | TCP_INT_CONFIG_FALSE); 522 | if (err) { 523 | fprintf(stderr, "Failed to set tracing to false in BPF map\n"); 524 | goto err; 525 | } 526 | 527 | err: 528 | /* If everything went okay, bpf object is pinned. 529 | * We can safely destroy local reference. 530 | */ 531 | tcp_int_bpf__destroy(tcp_int_obj); 532 | 533 | if (err && pinned) { 534 | tcp_int_unload(); 535 | } 536 | 537 | err = err ? TCP_INT_ERR_BPF : TCP_INT_OK; 538 | return err; 539 | } 540 | 541 | static int tcp_int_ecr_enable(bool enable) 542 | { 543 | if (enable) { 544 | return tcp_int_set_config(TCP_INT_CONFIG_KEY_ECR_DISABLE, 545 | TCP_INT_CONFIG_FALSE); 546 | } else { 547 | return tcp_int_set_config(TCP_INT_CONFIG_KEY_ECR_DISABLE, 548 | TCP_INT_CONFIG_TRUE); 549 | } 550 | } 551 | 552 | static int tcp_int_events_enable(bool enable) 553 | { 554 | if (enable) { 555 | return tcp_int_set_config(TCP_INT_CONFIG_KEY_TRACE_ENABLE, 556 | TCP_INT_CONFIG_TRUE); 557 | } else { 558 | return tcp_int_set_config(TCP_INT_CONFIG_KEY_TRACE_ENABLE, 559 | TCP_INT_CONFIG_FALSE); 560 | } 561 | } 562 | 563 | static __u64 tcp_int_get_tp(struct tcp_int_event *e) 564 | { 565 | __u64 intv = e->rate_interval_us; 566 | __u64 rate = e->rate_delivered; 567 | __u64 tp = 0; 568 | 569 | if (rate && intv) { 570 | /* MB/sec */ 571 | tp = rate * e->mss / intv; 572 | } 573 | 574 | return tp; 575 | } 576 | 577 | static void tcp_int_handle_event(void *ctx, int cpu, void *data, __u32 data_sz) 578 | { 579 | struct tcp_int_event *e = data; 580 | static __u64 start_ts = 0; 581 | char saddr[48]; 582 | char daddr[48]; 583 | 584 | if (sizeof(struct tcp_int_event) > data_sz) { 585 | fprintf(stderr, "unexpected event size (%lu != %u)\n", sizeof(*e), 586 | data_sz); 587 | return; 588 | } 589 | 590 | if (start_ts == 0) 591 | start_ts = e->ts_us; 592 | 593 | inet_ntop(e->family, &e->saddr, saddr, sizeof(saddr)); 594 | inet_ntop(e->family, &e->daddr, daddr, sizeof(daddr)); 595 | printf("%11.6f, %15s:%5d, %15s:%5d, %8d, %8d, %6d, %8lld, %14d, %8u, %9f, " 596 | "%3d, %11d, %21lld, %10d\n", 597 | (e->ts_us - start_ts) / 1000000.0, saddr, e->sport, daddr, e->dport, 598 | (e->srtt_us >> 3), (e->snd_cwnd * e->mss), e->total_retrans, 599 | tcp_int_get_tp(e), (tcp_int_ival_to_avail_bw(e->intval) * 1000), 600 | tcp_int_ival_to_qdepth(e->intval), 601 | tcp_int_hoplatecr_to_ns(e->hoplat) / 1000.0, e->hid, e->segs_out, 602 | e->bytes_acked, tcp_int_unmap_link_speed(e->link_speed)); 603 | } 604 | 605 | static void tcp_int_handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) 606 | { 607 | fprintf(stderr, "lost %llu events on CPU #%d\n", lost_cnt, cpu); 608 | } 609 | 610 | static void tcp_int_clean_hists(enum tcp_int_object_type type) 611 | { 612 | struct tcp_int_hist *tcp_int_empty_hists = NULL; 613 | DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts, .elem_flags = BPF_ANY, 614 | .flags = BPF_ANY, ); 615 | __u32 n_hists = TCP_INT_HIST_TYPE_MAX; 616 | int *keys = NULL; 617 | __u32 val_size; 618 | int hists_fd; 619 | int err; 620 | int i; 621 | 622 | switch (type) { 623 | case TCP_INT_OBJECT_MAP_HISTS: 624 | n_hists = TCP_INT_HIST_TYPE_MAX; 625 | break; 626 | case TCP_INT_OBJECT_MAP_HISTS_PERID: 627 | n_hists = TCP_INT_MAX_PERID_HISTS; 628 | break; 629 | default: 630 | return; 631 | } 632 | 633 | hists_fd = tcp_int_get_fd(type); 634 | if (hists_fd < 0) { 635 | return; 636 | } 637 | 638 | keys = malloc(n_hists * sizeof(int)); 639 | if (!keys) { 640 | goto cleanup; 641 | } 642 | val_size = (type == TCP_INT_OBJECT_MAP_HISTS) 643 | ? sizeof(struct tcp_int_hist) 644 | : sizeof(struct tcp_int_hist_perid); 645 | tcp_int_empty_hists = calloc(n_hists, val_size); 646 | if (!tcp_int_empty_hists) { 647 | goto cleanup; 648 | } 649 | for (i = 0; i < n_hists; i++) { 650 | keys[i] = i; 651 | } 652 | 653 | err = bpf_map_update_batch(hists_fd, keys, tcp_int_empty_hists, &n_hists, 654 | &opts); 655 | if (err < 0) { 656 | fprintf(stderr, "Failed to cleanup hist: %d\n", err); 657 | } 658 | 659 | cleanup: 660 | if (keys) { 661 | free(keys); 662 | } 663 | if (tcp_int_empty_hists) { 664 | free(tcp_int_empty_hists); 665 | } 666 | } 667 | 668 | static int tcp_int_get_hist_total_count(struct tcp_int_hist *hist) 669 | { 670 | int total_cnt = 0; 671 | int i; 672 | 673 | for (i = 0; i < TCP_INT_HIST_MAX_SLOTS; i++) { 674 | total_cnt += hist->slots[i]; 675 | } 676 | 677 | return total_cnt; 678 | } 679 | 680 | static void tcp_int_print_hist(struct tcp_int_hist *hist, 681 | enum tcp_int_hist_type type) 682 | { 683 | float pstep; 684 | 685 | printf("\n"); 686 | switch (type) { 687 | case TCP_INT_HIST_TYPE_SRTT: 688 | print_log2_hist(hist->slots, TCP_INT_HIST_MAX_SLOTS, -1, "SRTT [usec]"); 689 | break; 690 | case TCP_INT_HIST_TYPE_CWND: 691 | print_log2_hist(hist->slots, TCP_INT_HIST_MAX_SLOTS, -1, "CWND [pkts]"); 692 | break; 693 | case TCP_INT_HIST_TYPE_AVAILBW: 694 | print_linear_hist(hist->slots, TCP_INT_HIST_MAX_SLOTS, 0, 1, 0, -1, 695 | "AVAIL BW[Gbps]", false); 696 | break; 697 | case TCP_INT_HIST_TYPE_QDEPTH: 698 | print_log2_hist(hist->slots, TCP_INT_HIST_MAX_SLOTS, -1, "QDEPTH [KB]"); 699 | break; 700 | case TCP_INT_HIST_TYPE_HLAT: 701 | print_log2_hist(hist->slots, TCP_INT_HIST_MAX_SLOTS, -1, "HLAT [ns]"); 702 | break; 703 | case TCP_INT_HIST_TYPE_HID: 704 | print_linear_hist(hist->slots, TCP_INT_HIST_MAX_SLOTS, 0, 1, -1, -1, 705 | "SWITCH HOP", true); 706 | break; 707 | case TCP_INT_HIST_TYPE_RXSKBLEN: 708 | pstep = TCP_INT_MAX_SKBLEN / 709 | (TCP_INT_MAX_SKBLEN >> TCP_INT_SKBLEN_BITSHIFT); 710 | print_linear_hist(hist->slots, TCP_INT_HIST_MAX_SLOTS, 0, pstep, 0, -1, 711 | "RXSKBLEN [Bytes]", false); 712 | break; 713 | case TCP_INT_HIST_TYPE_TXSKBLEN: 714 | pstep = TCP_INT_MAX_SKBLEN / 715 | (TCP_INT_MAX_SKBLEN >> TCP_INT_SKBLEN_BITSHIFT); 716 | print_linear_hist(hist->slots, TCP_INT_HIST_MAX_SLOTS, 0, pstep, 0, -1, 717 | "TXSKBLEN [Bytes]", false); 718 | break; 719 | default: 720 | break; 721 | } 722 | } 723 | 724 | static int tcp_int_print_hists_perid(enum tcp_int_hist_type type_min, 725 | enum tcp_int_hist_type type_max) 726 | { 727 | struct tcp_int_hist_perid hists; 728 | int err = TCP_INT_OK; 729 | int hists_fd; 730 | int i; 731 | int j; 732 | 733 | hists_fd = tcp_int_get_fd(TCP_INT_OBJECT_MAP_HISTS_PERID); 734 | if (hists_fd < 0) { 735 | return TCP_INT_ERR_BPF; 736 | } 737 | 738 | for (i = 0; i < TCP_INT_MAX_PERID_HISTS; i++) { 739 | for (j = type_min; j <= type_max; j++) { 740 | err = bpf_map_lookup_elem(hists_fd, &j, &hists); 741 | if ((err < 0) || !tcp_int_get_hist_total_count(&hists.hist[i])) { 742 | break; 743 | } 744 | if (j == type_min) { 745 | printf("\n\n-- SWITCH HOP %2d " 746 | "-------------------------------------------------------" 747 | "------", 748 | i); 749 | } 750 | tcp_int_print_hist(&hists.hist[i], j); 751 | } 752 | } 753 | 754 | return err; 755 | } 756 | 757 | static int tcp_int_print_hists_pertype(enum tcp_int_hist_type type_min, 758 | enum tcp_int_hist_type type_max) 759 | { 760 | struct tcp_int_hist hist; 761 | int err = TCP_INT_OK; 762 | int hists_fd; 763 | int i; 764 | 765 | hists_fd = tcp_int_get_fd(TCP_INT_OBJECT_MAP_HISTS); 766 | if (hists_fd < 0) { 767 | return TCP_INT_ERR_BPF; 768 | } 769 | 770 | for (i = type_min; i <= type_max; i++) { 771 | err = bpf_map_lookup_elem(hists_fd, &i, &hist); 772 | if (err < 0) { 773 | break; 774 | } 775 | tcp_int_print_hist(&hist, i); 776 | } 777 | 778 | return err; 779 | } 780 | 781 | static int tcp_int_trace(void) 782 | { 783 | tcp_int_config_value trace_cfg_val_before; 784 | struct perf_buffer *pb = NULL; 785 | int err = TCP_INT_OK; 786 | 787 | err = tcp_int_get_config(TCP_INT_CONFIG_KEY_TRACE_ENABLE, 788 | &trace_cfg_val_before); 789 | if (err) { 790 | goto cleanup; 791 | } 792 | 793 | pb = perf_buffer__new(tcp_int_get_fd(TCP_INT_OBJECT_MAP_EVENTS), 794 | TCP_INT_PERF_BUFFER_PAGES, tcp_int_handle_event, 795 | tcp_int_handle_lost_events, NULL, NULL); 796 | err = libbpf_get_error(pb); 797 | if (err) { 798 | fprintf(stderr, "Failed to open perf buffer: %d\n", err); 799 | err = TCP_INT_ERR_BPF; 800 | goto cleanup; 801 | } 802 | 803 | err = tcp_int_set_config(TCP_INT_CONFIG_KEY_TRACE_ENABLE, 804 | TCP_INT_CONFIG_TRUE); 805 | if (err) { 806 | goto cleanup; 807 | } 808 | 809 | err = tcp_int_set_config(TCP_INT_CONFIG_KEY_GLOBAL_ENABLE, 810 | TCP_INT_CONFIG_TRUE); 811 | if (err) { 812 | goto cleanup; 813 | } 814 | 815 | printf("Tracing TCP-INT... Hit Ctrl-C to end.\n"); 816 | 817 | printf("%11s, %15s:%5s, %15s:%5s, %8s, %8s, %6s, %8s, %14s, %8s, %9s, %3s, " 818 | "%11s, %21s, %8s\n\n", 819 | "TIME(s)", "SIP", "SPORT", "DIP", "DPORT", "SRTT(US)", "CWND(B)", 820 | "LOST", "TP(MB/s)", "AVAILBW(Mb/s)", "QDEPTH(B)", "HLAT(us)", "HID", 821 | "SOUT", "BA", "LINKSPEED(Gb/s)"); 822 | 823 | while (!tcp_int_exiting) { 824 | err = perf_buffer__poll(pb, TCP_INT_PERF_POLL_TIMEOUT_MS); 825 | if (err < 0 && errno != EINTR) { 826 | fprintf(stderr, "Error polling perf buffer: %s\n", strerror(errno)); 827 | goto cleanup; 828 | } 829 | err = TCP_INT_OK; 830 | } 831 | 832 | cleanup: 833 | tcp_int_set_config(TCP_INT_CONFIG_KEY_TRACE_ENABLE, trace_cfg_val_before); 834 | perf_buffer__free(pb); 835 | return err; 836 | } 837 | 838 | static int tcp_int_hist(enum tcp_int_hist_type type_min, 839 | enum tcp_int_hist_type type_max, bool perid) 840 | { 841 | int err = TCP_INT_OK; 842 | 843 | tcp_int_clean_hists(TCP_INT_OBJECT_MAP_HISTS); 844 | tcp_int_clean_hists(TCP_INT_OBJECT_MAP_HISTS_PERID); 845 | 846 | err = 847 | tcp_int_set_config(TCP_INT_CONFIG_KEY_HIST_ENABLE, TCP_INT_CONFIG_TRUE); 848 | if (err) { 849 | goto cleanup; 850 | } 851 | 852 | err = tcp_int_set_config(TCP_INT_CONFIG_KEY_GLOBAL_ENABLE, 853 | TCP_INT_CONFIG_TRUE); 854 | if (err) { 855 | goto cleanup; 856 | } 857 | 858 | printf("Tracing TCP-INT... Hit Ctrl-C to end.\n"); 859 | 860 | while (!tcp_int_exiting) { 861 | sleep(1); 862 | } 863 | 864 | err = perid ? tcp_int_print_hists_perid(type_min, type_max) 865 | : tcp_int_print_hists_pertype(type_min, type_max); 866 | 867 | cleanup: 868 | tcp_int_set_config(TCP_INT_CONFIG_KEY_HIST_ENABLE, TCP_INT_CONFIG_FALSE); 869 | return err; 870 | } 871 | 872 | static int libbpf_print_fn(enum libbpf_print_level level, const char *format, 873 | va_list args) 874 | { 875 | return vfprintf(stdout, format, args); 876 | } 877 | 878 | static void tcp_int_sig_int(int signo) { tcp_int_exiting = 1; } 879 | 880 | int main(int argc, char **argv) 881 | { 882 | const char *cgroup_path = TCP_INT_CGROUP_PATH; 883 | int rv = TCP_INT_OK; 884 | 885 | if (argc < 2) { 886 | show_help(); 887 | return TCP_INT_OK; 888 | } 889 | 890 | if (argc == 3) { 891 | if (!strcmp(argv[2], "-d")) { 892 | libbpf_set_print(libbpf_print_fn); 893 | } else if (!strcmp(argv[2], "-c")) { 894 | fprintf(stderr, "Insufficient arguments provided\n"); 895 | return TCP_INT_ERR_SYS; 896 | } 897 | } 898 | if ((argc > 3) && (!strcmp(argv[2], "-c"))) { 899 | cgroup_path = validate_cgroup_path(argv[3]); 900 | if (!cgroup_path) { 901 | return TCP_INT_ERR_SYS; 902 | } 903 | } 904 | 905 | if (signal(SIGINT, tcp_int_sig_int) == SIG_ERR) { 906 | fprintf(stderr, "Can't set signal handler: %s\n", strerror(errno)); 907 | return TCP_INT_ERR_SYS; 908 | } 909 | 910 | if (!strcmp(argv[1], "load")) { 911 | rv = tcp_int_load(cgroup_path); 912 | } else if (!strcmp(argv[1], "unload")) { 913 | rv = tcp_int_unload(); 914 | } else if (!strcmp(argv[1], "enable")) { 915 | rv = tcp_int_set_config(TCP_INT_CONFIG_KEY_GLOBAL_ENABLE, 916 | TCP_INT_CONFIG_TRUE); 917 | } else if (!strcmp(argv[1], "disable")) { 918 | rv = tcp_int_set_config(TCP_INT_CONFIG_KEY_GLOBAL_ENABLE, 919 | TCP_INT_CONFIG_FALSE); 920 | } else if (!strcmp(argv[1], "trace")) { 921 | rv = tcp_int_trace(); 922 | } else if (!strcmp(argv[1], "hist")) { 923 | rv = tcp_int_hist(0, TCP_INT_HIST_TYPE_MAX, false); 924 | } else if (!strcmp(argv[1], "hist-rtt")) { 925 | rv = 926 | tcp_int_hist(TCP_INT_HIST_TYPE_SRTT, TCP_INT_HIST_TYPE_SRTT, false); 927 | } else if (!strcmp(argv[1], "hist-cwnd")) { 928 | rv = 929 | tcp_int_hist(TCP_INT_HIST_TYPE_CWND, TCP_INT_HIST_TYPE_CWND, false); 930 | } else if (!strcmp(argv[1], "hist-int")) { 931 | rv = tcp_int_hist(TCP_INT_HIST_TYPE_HID, TCP_INT_HIST_TYPE_QDEPTH, 932 | false); 933 | } else if (!strcmp(argv[1], "hist-int-perid")) { 934 | rv = tcp_int_hist(TCP_INT_HIST_TYPE_AVAILBW, TCP_INT_HIST_TYPE_QDEPTH, 935 | true); 936 | } else if (!strcmp(argv[1], "hist-qdepth")) { 937 | rv = tcp_int_hist(TCP_INT_HIST_TYPE_QDEPTH, TCP_INT_HIST_TYPE_QDEPTH, 938 | false); 939 | } else if (!strcmp(argv[1], "hist-availbw")) { 940 | rv = tcp_int_hist(TCP_INT_HIST_TYPE_AVAILBW, TCP_INT_HIST_TYPE_AVAILBW, 941 | false); 942 | } else if (!strcmp(argv[1], "hist-hoplat")) { 943 | rv = 944 | tcp_int_hist(TCP_INT_HIST_TYPE_HLAT, TCP_INT_HIST_TYPE_HLAT, false); 945 | } else if (!strcmp(argv[1], "hist-hid")) { 946 | rv = tcp_int_hist(TCP_INT_HIST_TYPE_HID, TCP_INT_HIST_TYPE_HID, false); 947 | } else if (!strcmp(argv[1], "hist-rxskblen")) { 948 | rv = tcp_int_hist(TCP_INT_HIST_TYPE_RXSKBLEN, 949 | TCP_INT_HIST_TYPE_RXSKBLEN, false); 950 | } else if (!strcmp(argv[1], "hist-txskblen")) { 951 | rv = tcp_int_hist(TCP_INT_HIST_TYPE_TXSKBLEN, 952 | TCP_INT_HIST_TYPE_TXSKBLEN, false); 953 | } else if (!strcmp(argv[1], "ecr-enable")) { 954 | rv = tcp_int_ecr_enable(true); 955 | } else if (!strcmp(argv[1], "ecr-disable")) { 956 | rv = tcp_int_ecr_enable(false); 957 | } else if (!strcmp(argv[1], "events-enable")) { 958 | rv = tcp_int_events_enable(true); 959 | } else if (!strcmp(argv[1], "events-disable")) { 960 | rv = tcp_int_events_enable(false); 961 | } else if (!strcmp(argv[1], "version")) { 962 | tcp_int_version(); 963 | } else { 964 | show_help(); 965 | } 966 | 967 | return rv; 968 | } 969 | -------------------------------------------------------------------------------- /code/src/tools/tcp_int.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2021-2022 Intel Corporation */ 2 | /* SPDX-License-Identifier: Apache-2.0 */ 3 | 4 | #ifndef __TCP_INT_H 5 | #define __TCP_INT_H 6 | 7 | /* Default paths and config */ 8 | #define TCP_INT_BPF_PIN_PATH "/sys/fs/bpf/tcp-int" 9 | #define TCP_INT_CGROUP_BASE_PATH \ 10 | "/sys/fs/cgroup/" // The base path is used for user input validation 11 | #define TCP_INT_CGROUP_PATH TCP_INT_CGROUP_BASE_PATH "cgroup.tcp-int" 12 | #define TCP_INT_PERF_BUFFER_PAGES 16 13 | #define TCP_INT_PERF_POLL_TIMEOUT_MS 100 14 | #define TCP_INT_HIST_MAX_EXTRA_HEADER_LEN 50 15 | 16 | /* Exit return codes */ 17 | #define TCP_INT_OK 0 18 | #define TCP_INT_ERR_BPF 40 19 | #define TCP_INT_ERR_SYS 41 20 | 21 | #endif /* __TCP_INT_H */ 22 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/models/go.mod: -------------------------------------------------------------------------------- 1 | module models 2 | 3 | go 1.15 4 | 5 | require ( 6 | google.golang.org/grpc v1.45.0 7 | google.golang.org/protobuf v1.27.1 8 | ) 9 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/models/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 5 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 6 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 7 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 8 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 9 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 10 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= 11 | github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 12 | github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 13 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 14 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 16 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 17 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 18 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 19 | github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= 20 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 21 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 22 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 23 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 24 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 25 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 26 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 27 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 28 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 29 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 30 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 31 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 32 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 33 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 34 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 35 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 36 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 37 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 38 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 39 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 40 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 41 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 42 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 43 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 44 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 45 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 46 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 47 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 48 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 49 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 50 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 51 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 52 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 53 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 54 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 55 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 56 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 57 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 58 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 59 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 60 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 61 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 62 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 63 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 64 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 65 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 66 | golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= 67 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 68 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 69 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 70 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 71 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 72 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 73 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 74 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 75 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 76 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 77 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= 78 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 79 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 80 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 81 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 82 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 83 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 84 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 85 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 86 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 87 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 88 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 89 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 90 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 91 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 92 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 93 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= 94 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 95 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 96 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 97 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 98 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 99 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 100 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 101 | google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= 102 | google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= 103 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 104 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 105 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 106 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 107 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 108 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 109 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 110 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 111 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 112 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 113 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 114 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 115 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 116 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 117 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 118 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 119 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 120 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 121 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 122 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/models/proto/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Protobuf code generation 3 | Use below command to generate Go code after changing the `.proto` files. 4 | ``` 5 | protoc --experimental_allow_proto3_optional \ 6 | --go_out=exporter/go --go_opt=paths=source_relative \ 7 | --go-grpc_out=exporter/go --go-grpc_opt=paths=source_relative \ 8 | exporter.proto 9 | ``` 10 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/models/proto/exporter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tcpint; 3 | 4 | option go_package = "/tcpint"; 5 | 6 | // TcpIntMsg is used in gRPC client/server communication. 7 | message TcpIntMsg { 8 | bytes ts_us = 1; 9 | optional uint32 family = 2; //address family type: 2 for ipv4, 10 for ipv6 10 | optional uint32 source_port = 3; 11 | optional uint32 destination_port = 4; 12 | string source_ip = 5; 13 | string destination_ip = 6; 14 | optional uint32 final_ttl = 7; //ttl of the packet at the hop with max int_value 15 | uint32 congestion_window = 8; //units: bytes(cwnd * mss) 16 | uint32 round_trip_time = 9; //units: nano seconds 17 | uint32 rate = 10; //units: pkts 18 | uint32 rate_interval = 11; //units: micro seconds 19 | uint32 max_segment_size = 12; //units: bytes 20 | uint32 int_value = 13; 21 | uint32 latencies_outgoing_sum = 14; //units: nano seconds 22 | uint32 latencies_return_sum = 15; //units: nano seconds 23 | uint32 queue_depth = 16; //qdepth when pkts was dequeued in the hop with highest queue depth 24 | uint32 bandwidth = 17; //units: MB/s 25 | double utilization = 18; //units: % utilization averaged over 1 second in the hop with highest link utilization 26 | uint32 count = 19; //required for druid not populated by tcpint client 27 | string timestamp = 20; //required for druid not populated by tcpint client 28 | optional uint32 initial_ttl = 21; //original ttl 29 | uint32 lost_out = 22; //lost packets(instantaneous) 30 | uint32 segs_out = 23; //number of segments out 31 | uint64 bytes_acked = 24; //number of bytes acked 32 | uint32 total_retrans = 25; //total lost packets(cumulative) 33 | optional uint32 hop_id = 26; 34 | uint32 available_bandwidth = 27; //units: MB/s 35 | uint32 link_speed = 28; //units: Gb/s 36 | } 37 | 38 | message TcpIntMsgs { 39 | repeated TcpIntMsg msgs = 1; 40 | } 41 | 42 | message TcpIntResponse { 43 | int32 status = 1; 44 | string message = 2; 45 | } 46 | 47 | service TcpIntService { 48 | rpc CreateTcpIntMsgs (TcpIntMsgs) returns (TcpIntResponse); 49 | } 50 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/models/proto/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright 2022 Intel Corporation 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | mkdir -p ./exporter/go 7 | 8 | # generate Go code 9 | protoc --experimental_allow_proto3_optional --go_out=exporter/go --go_opt=paths=source_relative \ 10 | --go-grpc_out=exporter/go --go-grpc_opt=paths=source_relative \ 11 | exporter.proto 12 | 13 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Intel Corporation 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | GIT_VERSION := $(shell git describe --abbrev=12 --tags) 5 | GIT_COMPILE_TIME := $(shell date -u '+%Y-%m-%dT%H:%M:%SZ') 6 | GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) 7 | 8 | GOLDFLAGS += -X main.version=$(GIT_VERSION) 9 | GOLDFLAGS += -X main.compileTime=$(GIT_COMPILE_TIME) 10 | GOLDFLAGS += -X main.gitBranch=$(GIT_BRANCH) 11 | GOFLAGS = -ldflags "$(GOLDFLAGS)" 12 | 13 | USER_TARGETS = tcp_int_exporter 14 | 15 | PREFIX ?= /usr/local 16 | INSTALLPATH = $(PREFIX)/lib/bpf/tcp-int/ 17 | 18 | all: clean build 19 | 20 | clean: 21 | go clean 22 | rm -f $(USER_TARGETS) 23 | 24 | build: 25 | go build -o tcp_int_exporter $(GOFLAGS) 26 | 27 | install: $(USER_TARGETS) 28 | install -d $(INSTALLPATH) 29 | install $^ $(INSTALLPATH) 30 | 31 | uninstall: $(USER_TARGETS) 32 | rm -f $(INSTALLPATH)$(USER_TARGETS) 33 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/README.md: -------------------------------------------------------------------------------- 1 | # tcpint exporter 2 | 3 | ### Tcp_int_exporter dependencies 4 | * go language (version tested go1.17.7) 5 | * protobuf(version 3.19.4) 6 | * Install Go pluggins. Installation instructions can be found at 7 | https://grpc.io/docs/languages/go/quickstart/ 8 | 9 | ### Compile and run the tcp_int_exporter 10 | ``` 11 | make clean 12 | make build 13 | make install 14 | /usr/local/lib/bpf/tcp-int/tcp_int_exporter --collector="0.0.0.0:30900" 15 | ``` 16 | 17 | ### Runtime configuration 18 | By default tcp_int_exporter tries to connect to the gRPC server using TLS. To 19 | change this for testing/development use the -use-tls flag. This is not recommended 20 | for production systems. 21 | ``` 22 | /usr/local/lib/bpf/tcp-int/tcp_int_exporter --collector="0.0.0.0:30900" -use-tls=false 23 | ``` 24 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/go.mod: -------------------------------------------------------------------------------- 1 | module tcp_int 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/cilium/ebpf v0.9.0 7 | google.golang.org/grpc v1.46.2 8 | ) 9 | 10 | require ( 11 | github.com/golang/protobuf v1.5.2 // indirect 12 | golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect 13 | golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 // indirect 14 | golang.org/x/text v0.3.3 // indirect 15 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect 16 | google.golang.org/protobuf v1.27.1 // indirect 17 | models v0.0.0-00010101000000-000000000000 // indirect 18 | ) 19 | 20 | replace models => ../models 21 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 5 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 6 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 7 | github.com/cilium/ebpf v0.9.0 h1:ldiV+FscPCQ/p3mNEV4O02EPbUZJFsoEtHvIr9xLTvk= 8 | github.com/cilium/ebpf v0.9.0/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= 9 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 10 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 11 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 12 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= 13 | github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 14 | github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 15 | github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 16 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 17 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 18 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 19 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 20 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 21 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 22 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 23 | github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= 24 | github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= 25 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 26 | github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= 27 | github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= 28 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 29 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 30 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 31 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 32 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 33 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 34 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 35 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 36 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 37 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 38 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 39 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 40 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 41 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 42 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 43 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 44 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 45 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 46 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 47 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 48 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 49 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 50 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 51 | github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= 52 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 53 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 54 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 55 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 56 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 57 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 58 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 59 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 60 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 61 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 62 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 63 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 64 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 65 | github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= 66 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 67 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 68 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 69 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 70 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 71 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 72 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 73 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 74 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 75 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 76 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 77 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 78 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 79 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 80 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 81 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 82 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 83 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 84 | golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= 85 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 86 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 87 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 88 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 89 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 90 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 91 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 92 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 93 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 94 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 95 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 96 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 97 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 98 | golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI= 99 | golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 100 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 101 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= 102 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 103 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 104 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 105 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 106 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 107 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 108 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 109 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 110 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 111 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 112 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 113 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 114 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 115 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 116 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= 117 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 118 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 119 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 120 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 121 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 122 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 123 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 124 | google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= 125 | google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ= 126 | google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= 127 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 128 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 129 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 130 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 131 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 132 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 133 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 134 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 135 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 136 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 137 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 138 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 139 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 140 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 141 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 142 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 143 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 144 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 145 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 146 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 147 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 148 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import ( 7 | "context" 8 | "flag" 9 | "log" 10 | "os" 11 | "strings" 12 | "time" 13 | 14 | pb "models/proto/exporter/go" 15 | "tcp_int/pkg/exporter" 16 | "tcp_int/pkg/secure" 17 | 18 | "github.com/cilium/ebpf" 19 | "github.com/cilium/ebpf/perf" 20 | 21 | "google.golang.org/grpc" 22 | ) 23 | 24 | var ( 25 | collector string 26 | ebpfMapFile string 27 | bufferSize int 28 | numWorkers int 29 | queueSize int 30 | timeout time.Duration 31 | useTls bool 32 | caCert string 33 | version string 34 | compileTime string 35 | gitBranch string 36 | ) 37 | 38 | func main() { 39 | flag.StringVar(&collector, "collector", "10.232.15.198:30900", "collector") 40 | flag.StringVar(&ebpfMapFile, "ebpf_map_file", "/sys/fs/bpf/tcp-int/map_tcp_int_events", "tcp int event map file path") 41 | flag.DurationVar(&timeout, "timeout", 30*time.Second, "gRPC timeout") 42 | flag.IntVar(&numWorkers, "num_workers", 10, "number of workers") 43 | flag.IntVar(&bufferSize, "buffer_size", 100, "ring buffer size") 44 | flag.IntVar(&queueSize, "queue_size", 1000, "message queue size") 45 | flag.BoolVar(&useTls, "use-tls", true, "Connect to server using TLS") 46 | flag.StringVar(&caCert, "ca-cert", "/ets/ssl/certs/tcp_int_ca_cert.pem", "Certificate of the CA that signed the collector's cert") 47 | flag.Parse() 48 | 49 | log.Printf("Compile Time: %s\n", compileTime) 50 | log.Printf("Version: %s\n", version) 51 | log.Printf("Git Branch: %s\n", gitBranch) 52 | 53 | if useTls && !secure.IsValidCert(caCert) { 54 | log.Fatalf("CA certificate '%s' does not appear to be a valid PEM certificate file", caCert) 55 | } 56 | 57 | ctx := context.Background() 58 | errChan := make(chan error, 0) 59 | 60 | var err error 61 | var conn *grpc.ClientConn 62 | 63 | proxyEnv := os.Getenv("https_proxy") 64 | 65 | if useTls { 66 | tlsCredentials, err := secure.LoadTLSCredentialsForClient(caCert) 67 | if err != nil { 68 | log.Fatal("cannot load TLS credentials: ", err) 69 | } 70 | conn, err = grpc.Dial(collector, 71 | grpc.WithTransportCredentials(tlsCredentials), 72 | grpc.WithNoProxy()) 73 | 74 | } else { 75 | 76 | if strings.Contains(proxyEnv, "http://localhost") { 77 | conn, err = grpc.Dial(collector, 78 | grpc.WithInsecure()) 79 | } else { 80 | conn, err = grpc.Dial(collector, 81 | grpc.WithInsecure(), 82 | grpc.WithNoProxy()) 83 | } 84 | } 85 | 86 | if err != nil { 87 | log.Fatalf("did not connect: %s", err) 88 | os.Exit(1) 89 | } 90 | defer conn.Close() 91 | // create gRPC client 92 | c := pb.NewTcpIntServiceClient(conn) 93 | 94 | // load ebpf map 95 | eventsMap, err := ebpf.LoadPinnedMap(ebpfMapFile, nil) 96 | if err != nil { 97 | log.Fatalf("failed to load map %s, err: %v \n", ebpfMapFile, err) 98 | os.Exit(1) 99 | } 100 | 101 | events, err := perf.NewReader(eventsMap, bufferSize) 102 | if err != nil { 103 | log.Fatalf("NewReader err: %v \n", err) 104 | os.Exit(1) 105 | } 106 | defer events.Close() 107 | 108 | // start tcp int exporter 109 | tcpintClient := exporter.NewTcpIntClient(events, c, numWorkers, queueSize) 110 | log.Printf("starting TCP-INT gRPC client...") 111 | go tcpintClient.Start(ctx, errChan) 112 | 113 | select { 114 | case <-ctx.Done(): 115 | log.Fatalf("context done: %v\n", ctx.Err()) 116 | os.Exit(1) 117 | case err := <-errChan: 118 | log.Fatalf("error running telemetry collector: %v\n", err) 119 | os.Exit(1) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/pkg/exporter/tcp_int_exporter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package exporter 5 | 6 | import ( 7 | "context" 8 | "fmt" 9 | "log" 10 | 11 | pb "models/proto/exporter/go" 12 | "tcp_int/pkg/parser" 13 | 14 | "github.com/cilium/ebpf/perf" 15 | ) 16 | 17 | type TcpIntClient struct { 18 | reader *perf.Reader 19 | client pb.TcpIntServiceClient 20 | 21 | workChan chan *pb.TcpIntMsg 22 | numWorkers int 23 | } 24 | 25 | func NewTcpIntClient(reader *perf.Reader, client pb.TcpIntServiceClient, numWorker int, queueSize int) *TcpIntClient { 26 | return &TcpIntClient{ 27 | reader: reader, 28 | client: client, 29 | numWorkers: numWorker, 30 | 31 | workChan: make(chan *pb.TcpIntMsg, queueSize), 32 | } 33 | } 34 | 35 | func (c *TcpIntClient) Start(ctx context.Context, errChan chan error) { 36 | 37 | // start the workers 38 | for i := 0; i < c.numWorkers; i++ { 39 | go c.work(ctx, c.workChan) 40 | } 41 | 42 | for { 43 | select { 44 | case <-ctx.Done(): 45 | errChan <- ctx.Err() 46 | default: 47 | //log.Printf("listening for events \n") 48 | record, err := c.reader.Read() 49 | if err != nil { 50 | fmt.Printf("failed to read record from eBPF map: %v \n", err) 51 | continue 52 | } 53 | //log.Printf("eBPF map record: %+v \n", record) 54 | 55 | if record.LostSamples != 0 { 56 | continue 57 | } 58 | 59 | msg, err := parser.Parse(record.RawSample) 60 | if err != nil { 61 | log.Printf("error parsing record, err: %v\n", err) 62 | continue 63 | } 64 | 65 | // send the msg 66 | c.workChan <- msg 67 | } 68 | } 69 | } 70 | 71 | func (c *TcpIntClient) work(ctx context.Context, workChan chan *pb.TcpIntMsg) { 72 | for { 73 | select { 74 | case <-ctx.Done(): 75 | return 76 | case msg := <-workChan: 77 | // log.Printf("sending gRPC message: %+v \n", msg) 78 | _, err := c.client.CreateTcpIntMsgs(ctx, &pb.TcpIntMsgs{Msgs: []*pb.TcpIntMsg{msg}}) 79 | if err != nil { 80 | log.Printf("error sending gRPC message, err: %v\n", err) 81 | continue 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/pkg/global/global.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package global 5 | 6 | import ( 7 | "bufio" 8 | "log" 9 | "os" 10 | "strconv" 11 | ) 12 | 13 | var InitialTtl uint32 14 | 15 | func init() { 16 | InitialTtl = ttlInitial() 17 | } 18 | 19 | func ttlInitial() uint32 { 20 | var init_ttl int 21 | //Reading default ttl from the server where exporter will be run 22 | f, err := os.Open("/proc/sys/net/ipv4/ip_default_ttl") 23 | if err != nil { 24 | log.Fatalf("unable to read file: %v", err) 25 | } 26 | defer f.Close() 27 | 28 | scanner := bufio.NewScanner(f) 29 | for scanner.Scan() { 30 | lineStr := scanner.Text() 31 | num, _ := strconv.Atoi(lineStr) 32 | init_ttl = num 33 | } 34 | return uint32(init_ttl) 35 | } 36 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/pkg/parser/parser.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package parser 5 | 6 | import ( 7 | "encoding/binary" 8 | "fmt" 9 | //"log" 10 | pb "models/proto/exporter/go" 11 | "tcp_int/pkg/global" 12 | "tcp_int/utils" 13 | ) 14 | 15 | const uint8Size = 1 16 | const uint16size = 2 17 | const uint32Size = 4 18 | const uint64Size = 8 19 | 20 | func Parse(data []byte) (*pb.TcpIntMsg, error) { 21 | timestampSize := uint64Size 22 | familySize := uint32Size 23 | sportSize := uint16size 24 | dportSize := uint16size 25 | saddrSize := 4 * uint32Size 26 | daddrSize := 4 * uint32Size 27 | cwndSize := uint32Size 28 | srttSize := uint32Size 29 | rateDeliveredSize := uint32Size 30 | rateIntervalSize := uint32Size 31 | mssSize := uint32Size 32 | hopLatSize := uint32Size 33 | returnHopLatSize := uint32Size 34 | intvalSize := uint8Size 35 | hopIdSize := uint8Size 36 | lostOutSize := uint32Size 37 | segsOutSize := uint32Size 38 | bytesAckedSize := uint64Size 39 | totalRetransSize := uint32Size 40 | linkSpeedSize := uint8Size 41 | 42 | perfEventSize := timestampSize + familySize + sportSize + 43 | dportSize + saddrSize + daddrSize + cwndSize + 44 | srttSize + rateDeliveredSize + rateIntervalSize + 45 | mssSize + hopLatSize + returnHopLatSize + intvalSize + 46 | hopIdSize + lostOutSize + segsOutSize + bytesAckedSize + 47 | totalRetransSize + linkSpeedSize 48 | 49 | if len(data) < perfEventSize { 50 | return nil, fmt.Errorf("invalid data format: %v", data) 51 | } 52 | 53 | tsUs := data[0:timestampSize] 54 | offset := timestampSize 55 | family := utils.NewUInt32(binary.LittleEndian.Uint32(data[offset:(offset + familySize)])) 56 | offset = offset + familySize 57 | sport := binary.LittleEndian.Uint16(data[offset:(offset + sportSize)]) 58 | offset = offset + sportSize 59 | dport := binary.LittleEndian.Uint16(data[offset:(offset + dportSize)]) 60 | offset = offset + dportSize 61 | saddr := data[offset:(offset + saddrSize)] 62 | offset = offset + saddrSize 63 | daddr := data[offset:(offset + daddrSize)] 64 | offset = offset + daddrSize 65 | cwnd := binary.LittleEndian.Uint32(data[offset:(offset + cwndSize)]) 66 | offset = offset + cwndSize 67 | srtt := binary.LittleEndian.Uint32(data[offset:(offset + srttSize)]) 68 | offset = offset + srttSize 69 | rate := binary.LittleEndian.Uint32(data[offset:(offset + rateDeliveredSize)]) 70 | offset = offset + rateDeliveredSize 71 | rateInterval := binary.LittleEndian.Uint32(data[offset:(offset + rateIntervalSize)]) 72 | offset = offset + rateIntervalSize 73 | maxSegmentSize := binary.LittleEndian.Uint32(data[offset:(offset + mssSize)]) 74 | offset = offset + mssSize 75 | lostOut := binary.LittleEndian.Uint32(data[offset:(offset + lostOutSize)]) 76 | offset = offset + lostOutSize 77 | intVal := uint32(data[offset]) 78 | offset = offset + intvalSize 79 | hopId := uint32(data[offset]) 80 | offset = offset + hopIdSize 81 | hopLat := binary.LittleEndian.Uint32(data[offset:(offset + hopLatSize)]) 82 | offset = offset + hopLatSize 83 | returnHopLat := binary.LittleEndian.Uint32(data[offset:(offset + returnHopLatSize)]) 84 | offset = offset + returnHopLatSize 85 | segsOut := binary.LittleEndian.Uint32(data[offset:(offset + segsOutSize)]) 86 | offset = offset + segsOutSize 87 | bytesAcked := binary.LittleEndian.Uint64(data[offset:(offset + bytesAckedSize)]) 88 | offset = offset + bytesAckedSize 89 | totalRetrans := binary.LittleEndian.Uint32(data[offset:(offset + totalRetransSize)]) 90 | offset = offset + totalRetransSize 91 | linkSpeed := uint32(data[offset]) 92 | msg := &pb.TcpIntMsg{ 93 | TsUs: tsUs, 94 | Family: family, 95 | SourcePort: utils.NewUInt32(uint32(sport)), 96 | DestinationPort: utils.NewUInt32(uint32(dport)), 97 | SourceIp: utils.GetIP(saddr, *family).String(), 98 | DestinationIp: utils.GetIP(daddr, *family).String(), 99 | CongestionWindow: cwnd * maxSegmentSize, 100 | RoundTripTime: srtt >> 3 * 1000, 101 | Rate: rate, 102 | RateInterval: rateInterval, 103 | MaxSegmentSize: maxSegmentSize, 104 | IntValue: intVal, 105 | FinalTtl: utils.NewUInt32(hopId), 106 | LatenciesOutgoingSum: hopLat * (1 << 8), 107 | LatenciesReturnSum: returnHopLat * (1 << 8), 108 | QueueDepth: parseQueueDepth(intVal), 109 | Bandwidth: parseBandwidthMBPS(rate, rateInterval, maxSegmentSize), 110 | Utilization: parseUtilizationPercentage(intVal), 111 | InitialTtl: utils.NewUInt32(global.InitialTtl), 112 | LostOut: lostOut, 113 | SegsOut: segsOut, 114 | BytesAcked: bytesAcked, 115 | TotalRetrans: totalRetrans, 116 | HopId: utils.NewUInt32(hopId), 117 | AvailableBandwidth: parseAvailableBandwidth(intVal), 118 | LinkSpeed: parseMappedLinkSpeed(linkSpeed), 119 | } 120 | 121 | //log.Printf("msg: %+v \n", msg) 122 | return msg, nil 123 | } 124 | 125 | func parseQueueDepth(intValue uint32) uint32 { 126 | var qd uint32 127 | if intValue >= 0x80 { 128 | qd = ((intValue & 0x7f) << 13) 129 | } else { 130 | qd = 0 131 | } 132 | return qd 133 | } 134 | 135 | func parseBandwidthMBPS(rate, rateInterval, maxSegmentSize uint32) uint32 { 136 | var bw uint32 137 | if rateInterval != 0 { 138 | bw = rate * maxSegmentSize / rateInterval 139 | } 140 | return bw 141 | } 142 | 143 | func parseUtilizationPercentage(intValue uint32) float64 { 144 | var ut float64 145 | if intValue >= 0x80 { 146 | ut = float64(100) 147 | } else { 148 | ut = float64(intValue << 3) 149 | } 150 | return ut 151 | } 152 | 153 | func parseAvailableBandwidth(intValue uint32) uint32 { 154 | var abw uint32 155 | if intValue >= 0x80 { 156 | abw = 0 157 | } else { 158 | abw = (uint32((0x80-1)-intValue) * 1000) / 8 159 | } 160 | return abw 161 | } 162 | 163 | func parseMappedLinkSpeed(linkSpeed uint32) uint32 { 164 | switch linkSpeed { 165 | case 1: 166 | return 10 167 | case 2: 168 | return 25 169 | case 3: 170 | return 40 171 | case 4: 172 | return 50 173 | case 5: 174 | return 100 175 | case 6: 176 | return 200 177 | case 7: 178 | return 400 179 | default: 180 | return 0 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/pkg/secure/secure.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package secure 5 | 6 | import ( 7 | "crypto/tls" 8 | "crypto/x509" 9 | "fmt" 10 | "io/ioutil" 11 | "path/filepath" 12 | 13 | "google.golang.org/grpc/credentials" 14 | ) 15 | 16 | func LoadTLSCredentialsForClient(certPath string) (credentials.TransportCredentials, error) { 17 | // Load certificate of the CA who signed server's certificate 18 | pemServerCA, err := ioutil.ReadFile(certPath) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | certPool := x509.NewCertPool() 24 | if !certPool.AppendCertsFromPEM(pemServerCA) { 25 | return nil, fmt.Errorf("failed to add server CA's certificate") 26 | } 27 | 28 | // Create the credentials and return it 29 | config := &tls.Config{ 30 | RootCAs: certPool, 31 | } 32 | 33 | return credentials.NewTLS(config), nil 34 | } 35 | 36 | func IsValidCert(cert string) bool { 37 | resolvedPath, _ := filepath.EvalSymlinks(cert) 38 | if filepath.Ext(resolvedPath) != ".pem" { 39 | return false 40 | } else { 41 | return true 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/tcp-int-exporter/src/tcp_int_exporter/utils/utils.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Intel Corporation 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package utils 5 | 6 | import ( 7 | "net" 8 | "time" 9 | ) 10 | 11 | const Layout = "2006-01-02T15:04:05.999999Z" 12 | 13 | func ConvertDateTimeToMilliSec(t time.Time) int64 { 14 | return t.UnixNano() / int64(time.Millisecond) 15 | } 16 | 17 | func ConvertMilliSecToDateTime(milli int64) time.Time { 18 | return time.Unix(0, milli*int64(time.Millisecond)) 19 | } 20 | 21 | func ConvertMicroSecToDateTime(milli int64) time.Time { 22 | return time.Unix(0, milli*int64(time.Microsecond)) 23 | } 24 | 25 | func ConvertDateTimeToNanoSec(t time.Time) int64 { 26 | return t.UnixNano() / int64(time.Nanosecond) 27 | } 28 | 29 | func ConvertNanoSecToDateTime(milli int64) time.Time { 30 | return time.Unix(0, milli*int64(time.Nanosecond)) 31 | } 32 | 33 | func NewInt64(x int64) *int64 { 34 | return &x 35 | } 36 | 37 | func NewUInt64(x uint64) *uint64 { 38 | return &x 39 | } 40 | 41 | func NewInt32(x int32) *int32 { 42 | return &x 43 | } 44 | 45 | func NewUInt32(x uint32) *uint32 { 46 | return &x 47 | } 48 | 49 | // GetIP returns either IPv4 or IPv6 base on the given input. 50 | func GetIP(arr []byte, family uint32) net.IP { 51 | var ip net.IP 52 | if family == 2 { 53 | ip = net.IPv4(arr[0], arr[1], arr[2], arr[3]) 54 | } else if family == 10 { 55 | ip = net.IP(arr) 56 | } 57 | return ip 58 | } 59 | --------------------------------------------------------------------------------