├── .gitignore ├── LICENSE ├── README.md ├── archetypes ├── default.md └── details.md ├── config.yaml ├── content ├── 10-welcome.md ├── 20-presenters.md ├── 21-book.md ├── 30-pre-requirements.md ├── 31-inspire.md ├── 32-environment-setup-tmux.md ├── 33-environment-tmux-cheat.md ├── 34-environment-vagrant.md ├── 35-environment-vagrant-cheatsheet.md ├── 36-environment-others.md ├── 42-intro-exercieses.md ├── 43-toc.md ├── 9999-thanks.md ├── bcc │ ├── 401-bcc-explanation.md │ ├── 402-bcc-tools.md │ ├── 403-bcc-hello-world.md │ ├── 404-bcc-hello-world-destilled.md │ ├── 405-bcc-perf-events.md │ ├── 406-bcc-perf-events-exercise-part-1.md │ ├── 407-bcc-perf-events-exercise-part-2.md │ ├── 408-bcc-perf-events-exercise-part-3.md │ ├── 409-bcc-perf-events-download-source.md │ ├── 410-bcc-profile.md │ ├── 411-bcc-profile-exercise.md │ ├── 412-bcc-profile-exercise-part-2.md │ ├── 499-bcc-takeaways.md │ └── intro.md ├── bpf-vm │ ├── 301-bpfvm-explaination.md │ ├── 302-bpfvm-diagram.md │ ├── 303-bpfvm-bpf-ebpf.md │ ├── 304-bpfvm-maps.md │ ├── 305-bpfvm-maps-types.md │ ├── 306-bpfvm-maps-operations.md │ ├── 320-bpfvm-programs.md │ ├── 321-bpfvm-program-helpers.md │ ├── 322-bpfvm-program-types.md │ ├── 323-bpfvm-program-exercice.md │ ├── 324-bpfvm-program-exercise-part-2.md │ ├── 325-bpfvm-program-exercise-part-3.md │ ├── 326-bpfvm-more-resources.md │ └── intro.md ├── bpftrace │ ├── 501-bpftrace.md │ ├── 502-bpftrace-install.md │ ├── 503-bpftrace-syntax.md │ ├── 505-bpftrace-probes.md │ ├── 510-bpftrace-probe-types-shortcuts.md │ ├── 515-bpftrace-filter.md │ ├── 516-bpftrace-actions.md │ ├── 517-bpftrace-functions.md │ ├── 518-bpftrace-functions-cont.md │ ├── 519-variable-types.md │ ├── 520-builtin-variables.md │ ├── 521-builtin-variables-contd.md │ ├── 523-bpftrace-exercise-tools.md │ ├── 524-bpftrace-exercise-tools-tcpretrans.md │ ├── 525-bpftrace-exercise-tools-tcpretrans-contd.md │ ├── 526-bpftrace-oneliner-read-kernel-tracing-vfs.md │ ├── 527-bpftrace-oneliner-read-syscall.md │ ├── 528-bpftrace-oneliner-uretprobe.md │ ├── 529-bpftrace-oneliner-uretprobe-contd.md │ ├── 590-bpftrace-internals.md │ ├── 598-bpftrace-takeaways.md │ ├── 599-bpftrace-credits.md │ └── intro.md ├── introduction │ ├── 101-introduction.md │ ├── 102-extended-bpf-implementation.md │ └── intro.md ├── kubernetes │ ├── 710-kubernetes-just-a-container.md │ ├── 711-kubernetes-kubectl-trace.md │ └── intro.md ├── networking │ ├── 1001-networking-intro.md │ ├── 1002-networking-tcpdump.md │ ├── 1003-networking-tcpdump-exercise.md │ ├── 1004-networking-tcpdump-exercise-result.md │ ├── 1005-networking-raw-sockets.md │ ├── 1006-networking-traffic-control.md │ ├── 1007-networking-traffic-control-clsbpf.md │ ├── 1008-networking-tc-example.md │ ├── 1028-networking-xdp.md │ ├── 1029-networking-xdp-tc-differences.md │ ├── 1030-networking-xdp-interactions.md │ ├── 1031-networking-xdp-example.md │ └── intro.md └── security │ ├── 1101-security-seccomp.md │ ├── 1102-security-lsm.md │ ├── 1103-security-seccomp-exercise.md │ └── intro.md ├── environment ├── .gitignore ├── README.md └── Vagrantfile ├── static ├── exercises │ └── mini_exec_snoop.py └── img │ ├── book_cover.jpg │ ├── bpf-vm-diagram.drawio │ ├── bpf-vm-diagram.svg │ ├── bpftrace-internals.png │ ├── bpftrace-syntax.png │ ├── kubernetes-kubectl-trace.png │ ├── probe.png │ ├── tc-flow-bpf-cls.png │ ├── tcpdump.png │ └── xdp-interaction-diagram.png └── themes └── workshop ├── layouts ├── _default │ ├── list.html │ └── single.html ├── index.html ├── partials │ ├── footer.html │ ├── header.html │ └── slides.html └── shortcodes │ ├── nav.html │ └── toc.html ├── static ├── images │ ├── extra-details.png │ ├── keyboard.png │ └── warning.png ├── remark-latest.min.js └── workshop.css └── theme.toml /.gitignore: -------------------------------------------------------------------------------- 1 | docs/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | For compatibility with the Linux Kernel licensing rules, 2 | all the C code (in files with extension *.c and *.h) in this repostiroy 3 | is licensed under GPL-2.0+ (GNU General Public License v2.0 or later). 4 | 5 | GPL-2.0: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html 6 | Kernel licensing rules: https://www.kernel.org/doc/html/latest/process/license-rules.html 7 | 8 | The rest of the code in this repository is licensed under the Apache License 9 | Version 2.0. You may obtain a copy of this license at: 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | The instructions and slides in this repository (e.g. the files 14 | with extension .md and .yml in the "slides" subdirectory) are 15 | under the Creative Commons Attribution 4.0 International Public 16 | License. You may obtain a copy of this license at: 17 | 18 | https://creativecommons.org/licenses/by/4.0/legalcode 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BPF Workshop 2 | 3 | Let's share some eBPF love! 4 | 5 | ## Authors 6 | 7 | - [David Calavera](https://github.com/calavera) 8 | - [Lorenzo Fontana](https://github.com/fntlnz) 9 | 10 | *Add your name here if you contributed to this workshop* 11 | 12 | ## Build and run 13 | 14 | You need [hugo](https://gohugo.io/) in your path, then 15 | 16 | ``` 17 | hugo serve 18 | ``` 19 | 20 | ## Thanks to 21 | 22 | - Many thanks to [Jérôme Petazzoni](https://github.com/jpetazzo), we adapted Jérôme's template 23 | from [container.training](https://container.training) to Hugo 24 | - Thanks to the [remark](https://github.com/gnab/remark) authors for their work on it, it's the tool 25 | we use to generate the slides. 26 | - Thanks to the [hugo](https://gohugo.io/) authors, for the awesome static site generator! 27 | -------------------------------------------------------------------------------- /archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | weight: 100 4 | --- 5 | 6 | # Hi I'm an example 7 | Let's do some eBPF 8 | 9 | .exercise[ 10 | bpf code 11 | ] 12 | -------------------------------------------------------------------------------- /archetypes/details.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | weight: 100 4 | class: extra-details 5 | --- 6 | 7 | # Extra details 8 | 9 | Your content here 10 | 11 | 12 | If you like emojis .emoji[🐕] 13 | -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | baseURL: "https://workshop.bpf.sh/" 2 | languageCode: "en-us" 3 | title: "BPF Workshop" 4 | theme: "workshop" 5 | publishDir: "docs" 6 | 7 | menu: 8 | main: 9 | - identifier: introduction 10 | weight: 100 11 | title: "Introduction" 12 | - identifier: bpf-vm 13 | weight: 300 14 | title: "The BPF in Kernel Virtual Machine" 15 | - identifier: bcc 16 | weight: 400 17 | title: "BCC" 18 | - identifier: bpftrace 19 | weight: 500 20 | title: "bpftrace" 21 | - identifier: kubernetes 22 | weight: 700 23 | title: "eBPF and Kubernetes" 24 | - identifier: networking 25 | weight: 1000 26 | title: "eBPF and Linux Networking" 27 | - identifier: security 28 | weight: 1100 29 | title: "Linux Kernel security and eBPF" 30 | -------------------------------------------------------------------------------- /content/10-welcome.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "welcome" 3 | weight: 10 4 | class: title 5 | --- 6 | 7 | Linux extended Berkeley Packet Filters 8 | 9 | 10 | .footnote[ 11 | **Be kind to the WiFi!**
12 | *Be kind with others*
13 | *Thank you!* 14 | 15 | **Slides: https://workshop.bpf.sh/** 16 | ] 17 | -------------------------------------------------------------------------------- /content/20-presenters.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "presenters" 3 | weight: 20 4 | class: extra-details 5 | --- 6 | 7 | - Hello! We are: 8 | 9 | - .emoji[🐕] David Calavera ([@calavera](https://twitter.com/calavera), Netlify) 10 | 11 | - .emoji[🐕] Lorenzo Fontana ([@fntlnz](https://twitter.com/fntlnz), Sysdig) 12 | 13 | - The workshop will run from 9:00am to 12:30pm 14 | 15 | - Feel free to interrupt for questions at any time 16 | -------------------------------------------------------------------------------- /content/21-book.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "book" 3 | weight: 21 4 | --- 5 | 6 | .pic[ 7 | ![BPF book cover](/img/book_cover.jpg) 8 | ] 9 | -------------------------------------------------------------------------------- /content/30-pre-requirements.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "requirements" 3 | weight: 30 4 | class: extra-details 5 | --- 6 | 7 | # Pre-requirements 8 | 9 | - A machine with Linux Kernel 4.18+ (or the provided Vagrant machine) 10 | 11 | - Be comfortable with the UNIX command line 12 | 13 | - navigating directories 14 | 15 | - editing files 16 | 17 | - a little bit of bash-fu (environment variables, loops) 18 | 19 | 20 | -------------------------------------------------------------------------------- /content/31-inspire.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "inspire" 3 | weight: 31 4 | class: title 5 | --- 6 | 7 | *Tell me and I forget.* 8 |
9 | *Teach me and I remember.* 10 |
11 | *Involve me and I learn.* 12 | 13 | Misattributed to Benjamin Franklin 14 | 15 | [(Probably inspired by Chinese Confucian philosopher Xunzi)](https://www.barrypopik.com/index.php/new_york_city/entry/tell_me_and_i_forget_teach_me_and_i_may_remember_involve_me_and_i_will_lear/) 16 | -------------------------------------------------------------------------------- /content/32-environment-setup-tmux.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "environment-setup-tmux" 3 | weight: 32 4 | --- 5 | 6 | # Terminals 7 | 8 | Once in a while, the instructions will say: 9 |
"Open a new terminal." 10 | 11 | There are multiple ways to do this: 12 | 13 | - create a new window or tab on your machine, and SSH into the VM; 14 | 15 | - use screen or tmux on the VM and open a new window from there; 16 | 17 | - Or if you are executing in a local Linux machine just open a new terminal in there; 18 | 19 | You are welcome to use the method that you feel the most comfortable with. 20 | 21 | -------------------------------------------------------------------------------- /content/33-environment-tmux-cheat.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "environment-tmux-cheat" 3 | weight: 33 4 | --- 5 | 6 | # Tmux cheatsheet 7 | 8 | [Tmux](https://en.wikipedia.org/wiki/Tmux) is a terminal multiplexer like `screen`. 9 | 10 | *You don't have to use it or even know about it to follow along. 11 |
12 | But some of us like to use it to switch between terminals. 13 |
14 | It comes preinstalled in the Vagrant machine we provided* 15 | 16 | - Ctrl-b c → creates a new window 17 | - Ctrl-b n → go to next window 18 | - Ctrl-b p → go to previous window 19 | - Ctrl-b " → split window top/bottom 20 | - Ctrl-b % → split window left/right 21 | - Ctrl-b Alt-1 → rearrange windows in columns 22 | - Ctrl-b Alt-2 → rearrange windows in rows 23 | - Ctrl-b arrows → navigate to other windows 24 | - Ctrl-b d → detach session 25 | - tmux attach → reattach to session 26 | 27 | -------------------------------------------------------------------------------- /content/34-environment-vagrant.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "environment-vagrant" 3 | weight: 34 4 | --- 5 | 6 | # Vagrant 7 | 8 | - If you don't know what Vagrant is, **don't worry**. 9 | - It's just a tool to create Virtual machines that we use to create a common VM with all the eBPF tools for everyone! 10 | - This workshop comes with a reference environment expressed in a `Vagrantfile`. 11 | - You don't have to use this one, but be prepared to install stuff! 12 | OS X 13 | 14 | ``` 15 | brew cask install virtualbox 16 | brew cask install vagrant 17 | ``` 18 | 19 | Windows 20 | 21 | Download [Vagrant](https://www.vagrantup.com/downloads.html) and [Virtualbox](https://www.virtualbox.org/) 22 | 23 | 24 | Ubuntu 25 | 26 | ``` 27 | apt install vagrant virtualbox 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /content/35-environment-vagrant-cheatsheet.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "environment-vagrant-cheatsheet" 3 | weight: 35 4 | --- 5 | 6 | # Vagrant 7 | 8 | After cloning the workshop repository, enter the environment folder: 9 | 10 | ``` 11 | git clone https://github.com/bpftools/bpf-workshop.git 12 | cd bpf-workshop/environment 13 | ``` 14 | 15 | Then there are three major things you can do: 16 | 17 | ```bash 18 | # Start the environment 19 | vagrant up 20 | 21 | # Stop the environment 22 | vagrant halt 23 | 24 | # Destroy the environment 25 | vagrant destroy 26 | 27 | # Obtain a shell 28 | vagrant ssh 29 | ``` 30 | -------------------------------------------------------------------------------- /content/36-environment-others.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "environment-others" 3 | weight: 35 4 | --- 5 | 6 | # Non-Vagrant (aka. All the other environments) 7 | 8 | Make sure to have: 9 | 10 | - git 11 | - an editor of your choice 12 | - gcc 13 | - clang 14 | - go 15 | 16 | The other tools we need, `bpftrace` and `bcc` will have their own setup 17 | instructions in the respective chapters. 18 | -------------------------------------------------------------------------------- /content/42-intro-exercieses.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "intro-exercises" 3 | weight: 42 4 | --- 5 | 6 | ## Hands-on sections 7 | 8 | - The whole workshop is hands-on 9 | 10 | - We are going to write some eBPF programs 11 | 12 | - All hands-on sections are clearly identified, like the gray rectangle below 13 | 14 | .exercise[ 15 | - This is the stuff you're supposed to do! 16 | ] 17 | -------------------------------------------------------------------------------- /content/43-toc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "toc" 3 | weight: 43 4 | --- 5 | 6 | # Table of content 7 | 8 | {{< toc >}} 9 | -------------------------------------------------------------------------------- /content/9999-thanks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "credits" 3 | weight: 9999 4 | class: extra-details 5 | --- 6 | 7 | ## Credits 8 | 9 | - Thanks to all the eBPF authors and tools makers for their awesome work on it; 10 | - Many thanks to [Jérôme Petazzoni](https://github.com/jpetazzo), we adapted Jérôme's template 11 | from [container.training](https://container.training) to Hugo, we also used the terminals setup instructions and the tmux cheatsheet from that deck! 12 | - Thanks to the [remark](https://github.com/gnab/remark) authors for their work on it, it's the tool 13 | we use to generate the slides; 14 | - Thanks to the [hugo](https://gohugo.io/) authors, for the awesome static site generator; 15 | 16 | -------------------------------------------------------------------------------- /content/bcc/401-bcc-explanation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-explaination" 3 | weight: 401 4 | --- 5 | 6 | # The BPF Compiler Collection 7 | 8 | - Toolkit to create and manipulate BPF programs 9 | - Connects BPF programs with high level programming languages 10 | - C++, Python, Lua, and Go frontends 11 | - Dynamic load and unload of BPF programs 12 | -------------------------------------------------------------------------------- /content/bcc/402-bcc-tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-tools" 3 | weight: 402 4 | --- 5 | 6 | # BCC included tools 7 | 8 | - Tracing and monitoring 9 | - Networking 10 | - Introspection 11 | -------------------------------------------------------------------------------- /content/bcc/403-bcc-hello-world.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-hello-world" 3 | weight: 403 4 | --- 5 | 6 | # BCC hello world 7 | 8 | .exercise[ 9 | - In the `bcc/examples` folder; 10 | - With root permissions; 11 | - Execute the `hello_world.py` tool; 12 | ] 13 | -------------------------------------------------------------------------------- /content/bcc/404-bcc-hello-world-destilled.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-hello-world-destilled" 3 | weight: 404 4 | --- 5 | 6 | # BCC hello world destilled 7 | 8 | ``` 9 | source = """ 10 | int kprobe__sys_clone(void *ctx) { 11 | bpf_trace_printk("Hello, World!\n"); 12 | return 0; 13 | } 14 | """ 15 | 16 | BPF(text = source).trace_print() 17 | ``` 18 | -------------------------------------------------------------------------------- /content/bcc/405-bcc-perf-events.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-perf-events" 3 | weight: 405 4 | --- 5 | 6 | # BCC perf events 7 | 8 | - Real time event service between BPF and frontend. 9 | - Active buffer polling 10 | -------------------------------------------------------------------------------- /content/bcc/406-bcc-perf-events-exercise-part-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-perf-events-exercise-1" 3 | weight: 406 4 | --- 5 | 6 | # BCC perf events exercise (part 1) 7 | 8 | .exercise[ 9 | ``` 10 | bpf_source = """ 11 | #include 12 | 13 | BPF_PERF_OUTPUT(events); 14 | 15 | struct data_t { 16 | char comm[16]; 17 | }; 18 | """ 19 | ``` 20 | ] 21 | -------------------------------------------------------------------------------- /content/bcc/407-bcc-perf-events-exercise-part-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-perf-events-exercise-1" 3 | weight: 406 4 | --- 5 | 6 | # BCC perf events exercise (part 2) 7 | 8 | .exercise[ 9 | ``` 10 | bpf_source += """ 11 | int on_execve(struct pt_regs *ctx, 12 | const char __user *filename, 13 | const char __user *const __user *__argv, 14 | const char __user *const __user *__envp) 15 | { 16 | struct data_t data = {}; 17 | bpf_get_current_comm(&data.comm, sizeof(data.comm)); 18 | 19 | events.perf_submit(ctx, &data, sizeof(data)); 20 | return 0; 21 | } 22 | """ 23 | ``` 24 | ] 25 | -------------------------------------------------------------------------------- /content/bcc/408-bcc-perf-events-exercise-part-3.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-perf-events-exercise-3" 3 | weight: 408 4 | --- 5 | 6 | # BCC perf events exercise (part 3) 7 | .exercise[ 8 | ``` 9 | from bcc import BPF 10 | from bcc.utils import printb 11 | 12 | def dump_data(cpu, data, size): 13 | event = bpf["events"].event(data) 14 | printb(b"%-16s" % event.comm) 15 | 16 | bpf = BPF(text = bpf_source) 17 | execve_function = bpf.get_syscall_fnname("execve") 18 | bpf.attach_kprobe(event = execve_function, fn_name = "on_execve") 19 | 20 | bpf["events"].open_perf_buffer(dump_data) 21 | while 1: 22 | bpf.perf_buffer_poll() 23 | ``` 24 | ] 25 | -------------------------------------------------------------------------------- /content/bcc/409-bcc-perf-events-download-source.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-perf-events-source" 3 | weight: 409 4 | --- 5 | 6 | # BCC perf events source 7 | 8 | https://workshop.bpf.sh/exercises/mini_exec_snoop.py 9 | -------------------------------------------------------------------------------- /content/bcc/410-bcc-profile.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-profile" 3 | weight: 410 4 | --- 5 | 6 | # BCC Profile 7 | 8 | - Sample stack traces to profile CPU data 9 | - Observe where a running application is spending CPU time 10 | -------------------------------------------------------------------------------- /content/bcc/411-bcc-profile-exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-profile-exercise" 3 | weight: 411 4 | --- 5 | 6 | # BCC Profile exercise 7 | 8 | .exercise[ 9 | ``` 10 | sudo tools/profile -p PID 11 | ``` 12 | ] 13 | -------------------------------------------------------------------------------- /content/bcc/412-bcc-profile-exercise-part-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-profile-exercise" 3 | weight: 412 4 | --- 5 | 6 | # BCC Profile exercise (Part 2) 7 | 8 | .exercise[ 9 | - Download the Flamegrapsh scripts: 10 | 11 | ``` 12 | git clone https://github.com/brendangregg/FlameGraph 13 | ``` 14 | 15 | - Generate a flamegraph for your profiled data: 16 | 17 | ``` 18 | sudo tools/profile -p PID -f > /tmp/profile.out 19 | 20 | flamegraph.pl /tmp/profile.out > /tmp/profile-graph.svg \ 21 | && firefox /tmp/profile-graph.svg 22 | ``` 23 | ] 24 | -------------------------------------------------------------------------------- /content/bcc/499-bcc-takeaways.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc-takeaways" 3 | weight: 499 4 | --- 5 | 6 | # Takeaways 7 | 8 | - Convenient interop with other languages 9 | - Write one time only tools, and background processes 10 | 11 | -------------------------------------------------------------------------------- /content/bcc/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bcc" 3 | weight: 400 4 | class: title 5 | 6 | --- 7 | {{< nav >}} 8 | 9 | -------------------------------------------------------------------------------- /content/bpf-vm/301-bpfvm-explaination.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-explaination" 3 | weight: 301 4 | --- 5 | 6 | # The BPF in-kernel Virtual Machine 7 | 8 | - Implements a general purpose low level RISC instructions 9 | - Runs the instructions in response to events triggered by the kernel 10 | - Implements a verifier, so that your programs can't break the kernel 11 | - Has different interfaces for different types of programs 12 | - Widely supported in the kernel 13 | - Has an upstream LLVM backend, you can compile eBPF code with clang 14 | -------------------------------------------------------------------------------- /content/bpf-vm/302-bpfvm-diagram.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-diagram" 3 | weight: 302 4 | --- 5 | 6 | # The BPF in-kernel Virtual Machine 7 | 8 | .pic[ 9 | ![eBPF Virtual Machine Diagram](/img/bpf-vm-diagram.svg) 10 | ] 11 | -------------------------------------------------------------------------------- /content/bpf-vm/303-bpfvm-bpf-ebpf.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-ebpf" 3 | weight: 303 4 | --- 5 | 6 | # BPF ... eBPF ... .emoji[🤔] 7 | 8 | - BPF is the classic implementation, suitable only for basic filtering, BPF is also referred as cBPF; 9 | - The eBPF instruction set is wider than the BPF instruction set; 10 | - BPF does not support maps, eBPF does; 11 | - eBPF has general purpose registers and a stack, BPF only an accumulator and a scratch memory store; 12 | -------------------------------------------------------------------------------- /content/bpf-vm/304-bpfvm-maps.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-maps" 3 | weight: 304 4 | --- 5 | 6 | # Maps 7 | 8 | - BPF Maps data stores that live in the kernel; 9 | - Can be accessed by any BPF program that knows about them; 10 | - Programs that run in user-space can also access these maps by using file descriptors; 11 | - You can store any kind of data in a map, as long as you specify the data size correctly before hand; 12 | - The kernel treats keys and values as binary blobs and it doesn’t care about what you keep in a map; 13 | - This is what we use to let userspace programs to extract or feed information into BPF programs running in the kernel! 14 | 15 | -------------------------------------------------------------------------------- /content/bpf-vm/305-bpfvm-maps-types.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-maps-types" 3 | weight: 305 4 | --- 5 | 6 | **Many different types of maps** 7 | 8 | - Hash table: BPF_MAP_TYPE_HASH 9 | - Array: BPF_MAP_TYPE_ARRAY 10 | - Program array maps: BPF_MAP_TYPE_PROG_ARRAY, this one is magic, allows you to store references to bpf programs so that you can do jumps between bpf programs; 11 | - Perf events array maps: BPF_MAP_TYPE_PERF_EVENT_ARRAY 12 | - Per-CPU hash maps: BPF_MAP_TYPE_PERCPU_HASH 13 | - Per-CPU array maps: BPF_MAP_TYPE_PERCPU_ARRAY 14 | - Stack trace maps: BPF_MAP_TYPE_STACK_TRACE 15 | - Cgroup array maps: BPF_MAP_TYPE_CGROUP_ARRAY 16 | - Hash and per cpu has with LRU cache: BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_LRU_HASH 17 | - Longest Prefix Match(LPM) Trie: BPF_MAP_TYPE_LPM_TRIE 18 | - Array of maps, and hash of maps, maps: `BPF_MAP_TYPE_ARRAY_OF_MAPS` and `BPF_MAP_TYPE_HASH_OF_MAPS` 19 | - And many more! Find all of them `man 2 bpf` 20 | -------------------------------------------------------------------------------- /content/bpf-vm/306-bpfvm-maps-operations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-maps-operations" 3 | weight: 306 4 | --- 5 | 6 | **Maps operations** 7 | 8 | - Lookup a single element value, `bpf_map_lookup_elem` 9 | - Remove an element, `bpf_map_delete_element` 10 | - Iterating over elements 11 | - Updating an element, `bpf_map_update_elem` 12 | - Get the next key in the map, `bpf_map_get_next_key` 13 | - Search, get the value and delete in a single atomic operation, `bpf_map_lookup_and_delete_element` 14 | - Concurrent access is regulated using a mechanism called `bpf_spin_lock` that is essentially a semaphore; 15 | -------------------------------------------------------------------------------- /content/bpf-vm/320-bpfvm-programs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-programs" 3 | weight: 320 4 | --- 5 | 6 | # BPF programs 7 | 8 | - Code that's triggered based on events in the kernel 9 | - Context arguments that depend on the event triggered 10 | - Must always terminate 11 | - Cannot include outbounded control loops 12 | - Limited in the number of instructions to execute (changing soon) 13 | - Can trigger other BPF programs 14 | -------------------------------------------------------------------------------- /content/bpf-vm/321-bpfvm-program-helpers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-program-helpers" 3 | weight: 321 4 | --- 5 | 6 | # BPF program helpers 7 | 8 | - General helpers available to any program, like `bpf_trace_printk` and `bpf_get_current_pid_tgid` 9 | - Specialized helper available only to specific types of programs, `bpf_perf_event_output` 10 | - https://github.com/iovisor/bpf-docs/blob/master/bpf_helpers.rst 11 | -------------------------------------------------------------------------------- /content/bpf-vm/322-bpfvm-program-types.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-program-types" 3 | weight: 322 4 | --- 5 | 6 | # BPF program types 7 | 8 | - Socket filtering: BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_SK_SKB, BPF_PROG_TYPE_SK_MSG, BPF_PROG_TYPE_SK_REUSEPORT 9 | - Tracing: BPF_PROG_TYPE_KPROBE, BPF_PROG_TYPE_TRACEPOINT, BPF_PROG_TYPE_RAW_TRACEPOINT 10 | - XDP: BPF_PROG_TYPE_XDP 11 | - Perf events: BPF_PROG_TYPE_PERF_EVENT 12 | - Cgroups: BPF_PROG_TYPE_CGROUP_SKB, BPF_PROG_TYPE_CGROUP_SOCK, BPF_PROG_TYPE_CGROUP_DEVICE, BPF_PROG_TYPE_CGROUP_SOCK_ADDR 13 | - Infrared devices: BPF_PROG_TYPE_LIRC_MODE2 14 | -------------------------------------------------------------------------------- /content/bpf-vm/323-bpfvm-program-exercice.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-program-exercise" 3 | weight: 323 4 | --- 5 | 6 | # BPF program example 7 | 8 | .exercise[ 9 | ``` 10 | #include 11 | #define SEC(NAME) __attribute__((section(NAME), used)) 12 | 13 | SEC("tracepoint/syscalls/sys_enter_execve") 14 | int bpf_prog(void *ctx) { 15 | char msg[] = "Hello, BPF World!"; 16 | bpf_trace_printk(msg, sizeof(msg)); 17 | return 0; 18 | } 19 | 20 | char _license[] SEC("license") = "GPL"; 21 | ``` 22 | ] 23 | -------------------------------------------------------------------------------- /content/bpf-vm/324-bpfvm-program-exercise-part-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-program-exercise" 3 | weight: 324 4 | --- 5 | 6 | # BPF program example (part 2) 7 | 8 | .exercise[ 9 | ``` 10 | clang -O2 -target bpf -c hello_world_kern.c -o hello_world_kern.o 11 | ``` 12 | ] 13 | -------------------------------------------------------------------------------- /content/bpf-vm/325-bpfvm-program-exercise-part-3.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-program-exercise" 3 | weight: 325 4 | --- 5 | 6 | # BPF program example (part 3) 7 | 8 | .exercise[ 9 | ``` 10 | #include 11 | #include "bpf_load.h" 12 | 13 | int main(int argc, char **argv) { 14 | if (load_bpf_file("hello_world_kern.o") != 0) { 15 | printf("The kernel didn't load the BPF program\\n"); 16 | return -1; 17 | } 18 | read_trace_pipe(); 19 | return 0; 20 | } 21 | ``` 22 | ] 23 | -------------------------------------------------------------------------------- /content/bpf-vm/326-bpfvm-more-resources.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpfvm-bpf-program-resources" 3 | weight: 327 4 | --- 5 | 6 | # Other resources 7 | 8 | - https://bpf.sh/usdt-report-doc 9 | - https://fntlnz.wtf/post/xdp-ip-iproute/ 10 | -------------------------------------------------------------------------------- /content/bpf-vm/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpf-vm" 3 | weight: 300 4 | class: title 5 | 6 | --- 7 | {{< nav >}} 8 | 9 | -------------------------------------------------------------------------------- /content/bpftrace/501-bpftrace.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-intro" 3 | weight: 501 4 | --- 5 | 6 | # bpftrace: BPF observability front-end 7 | 8 | On GitHub https://github.com/iovisor/bpftrace 9 | 10 | *What it is*: 11 | 12 | - Higher level language to write eBPF programs; 13 | - Built from the ground-up for BPF and Linux; 14 | - Used in production at Netflix, Facebook, etc; 15 | - Custom one-liners; 16 | - Comes with tools; 17 | - It is just for tracing; 18 | 19 | *What it is NOT*: 20 | 21 | - A framework to build your loaders; 22 | - You can't do classic bpf with it (like seccomp programs or socket probe types); 23 | - It does not support traffic control and XDP; 24 | 25 | 26 | -------------------------------------------------------------------------------- /content/bpftrace/502-bpftrace-install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-install" 3 | weight: 502 4 | --- 5 | 6 | # bpftrace: Installation 7 | 8 | We will need to do some exercises with bpftrace. 9 | If you are not using the Vagrant environment, you might want to install it now! 10 | 11 | Ubuntu snap package 12 | 13 | ``` 14 | sudo snap install --devmode bpftrace 15 | sudo snap connect bpftrace:system-trace 16 | ``` 17 | 18 | Fedora (28 or later) 19 | 20 | ``` 21 | sudo dnf install bpftrace 22 | ``` 23 | 24 | You can find further instructions [here](https://github.com/iovisor/bpftrace/blob/master/INSTALL.md) 25 | 26 | 27 | -------------------------------------------------------------------------------- /content/bpftrace/503-bpftrace-syntax.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-syntax" 3 | weight: 503 4 | --- 5 | 6 | # bpftrace: Syntax 7 | 8 | .pic[ 9 | ![bpftrace-syntax](/img/bpftrace-syntax.png) 10 | ] 11 | -------------------------------------------------------------------------------- /content/bpftrace/505-bpftrace-probes.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "bpftrace-probes" 4 | weight: 505 5 | --- 6 | 7 | # bpftrace: Probes 8 | 9 | .pic[ 10 | ![supported bpf probe types](/img/probe.png) 11 | ] 12 | -------------------------------------------------------------------------------- /content/bpftrace/510-bpftrace-probe-types-shortcuts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "probe type shortcuts" 3 | weight: 510 4 | --- 5 | 6 | # bpftrace: Probe type shortcuts 7 | 8 | | full | shortcut | Description | 9 | |------------|-----------|---------------------------------------| 10 | | tracepoint | t | Kernel static tracepoints | 11 | | usdt | U | User-level statically defined tracing | 12 | | kprobe | k | Kernel function tracing | 13 | | kretprobe | kr | Kernel function returns | 14 | | uprobe | u | User-level function tracing | 15 | | uretprobe | ur | User-level function returns | 16 | | profile | p | Timed sampling across all CPUs | 17 | | interval | i | Interval output | 18 | | software | s | Kernel software events | 19 | | hardware | h | Processor hardware events | 20 | -------------------------------------------------------------------------------- /content/bpftrace/515-bpftrace-filter.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "bpftrace-filters" 4 | weight: 515 5 | --- 6 | 7 | # bpftrace: Filters 8 | 9 | - /pid == 181/ 10 | - /comm != “sshd”/ 11 | - /@ts[tid]/ 12 | 13 | -------------------------------------------------------------------------------- /content/bpftrace/516-bpftrace-actions.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "bpftrace-actions" 4 | weight: 516 5 | --- 6 | 7 | # bpftrace: Actions 8 | 9 | **Per-event output** 10 | 11 | - printf() 12 | - system() 13 | - join() 14 | - time() 15 | 16 | **Map Summaries** 17 | 18 | - @ = count() or @++ 19 | - @ = hist() 20 | 21 | -------------------------------------------------------------------------------- /content/bpftrace/517-bpftrace-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-functions" 3 | weight: 517 4 | --- 5 | 6 | # bpftrace: Functions 7 | 8 | | function | description | 9 | |------------------------------------------|--------------------------------------------------------| 10 | | hist(int n) | Produce a log2 histogram of values of n | 11 | | lhist(int n# int min# int max# int step) | Produce a linear histogram of values of n | 12 | | count() | Count the number of times this function is called | 13 | | sum(int n) | Sum this value | 14 | | min(int n) | Record the minimum value seen | 15 | | max(int n) | Record the maximum value seen | 16 | | avg(int n) | Average this value | 17 | | stats(int n) | Return the count# average# and total for this value | 18 | | delete(@x) | Delete the map element passed in as an argument | 19 | | str(char *s [# int length]) | Returns the string pointed to by s | 20 | | printf(char *fmt# ...) | Print formatted to stdout | 21 | -------------------------------------------------------------------------------- /content/bpftrace/518-bpftrace-functions-cont.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-functions-contd" 3 | weight: 518 4 | --- 5 | 6 | # bpftrace: Functions (cont'd) 7 | 8 | | function | description | 9 | |------------------------------------------|--------------------------------------------------------| 10 | | print(@x[# int top [# int div]]) | Print a map# with optional top entry count and divisor | 11 | | clear(@x) | Delete all key/values from a map | 12 | | sym(void *p) | Resolve kernel address | 13 | | usym(void *p) | Resolve user space address | 14 | | ntop([int af# ]int|char[4|16] addr) | Resolve ip address | 15 | | kaddr(char *name) | Resolve kernel symbol name | 16 | | uaddr(char *name) | Resolve user space symbol name | 17 | | reg(char *name) | Returns the value stored in the named register | 18 | | join(char *arr[] [# char *delim]) | Prints the string array | 19 | | time(char *fmt) | Print the current time | 20 | | cat(char *filename) | Print file content | 21 | | system(char *fmt) | Execute shell command | 22 | | exit() | Quit bpftrace | 23 | -------------------------------------------------------------------------------- /content/bpftrace/519-variable-types.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-variable-types" 3 | weight: 519 4 | --- 5 | 6 | # bpftrace: Variable types 7 | 8 | **Basic Variables** 9 | 10 | - @global 11 | - @thread_local[tid] 12 | - $scratch 13 | 14 | **Associative Arrays** 15 | 16 | - @array[key] = value 17 | 18 | **Buitins** 19 | 20 | - pid 21 | - ... 22 | -------------------------------------------------------------------------------- /content/bpftrace/520-builtin-variables.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-builtin-variables" 3 | weight: 520 4 | --- 5 | 6 | # bpftrace: Builtin Variables 7 | 8 | | variable | description | 9 | |----------------------|----------------------------------------------------| 10 | | tid | Thread ID (kernel pid) | 11 | | cgroup | Cgroup ID of the current process | 12 | | uid | User ID | 13 | | gid | Group ID | 14 | | nsecs | Nanosecond timestamp | 15 | | elapsed | Nanosecond timestamp since bpftrace initialization | 16 | | cpu | Processor ID | 17 | | comm | Process name | 18 | -------------------------------------------------------------------------------- /content/bpftrace/521-builtin-variables-contd.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-builtin-variables-contd" 3 | weight: 521 4 | --- 5 | 6 | # bpftrace: Builtin Variables (cont'd) 7 | 8 | | variable | description | 9 | |----------------------|----------------------------------------------------| 10 | | pid | Process ID (kernel tgid) | 11 | | stack | Kernel stack trace | 12 | | ustack | User stack trace | 13 | | arg0, arg1, ... etc. | Arguments to the function being traced | 14 | | retval | Return value from function being traced | 15 | | func | Name of the function currently being traced | 16 | | probe | Full name of the probe | 17 | | curtask | Current task_struct as a u64 | 18 | | rand | Random number of type u32 | 19 | | $1, $2, ... etc. | Positional parameters to the bpftrace program | 20 | -------------------------------------------------------------------------------- /content/bpftrace/523-bpftrace-exercise-tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-exercise-tools" 3 | weight: 523 4 | class: extra-details 5 | --- 6 | 7 | ## bpftrace hands on: Tools! 8 | 9 | 1. We will clone the bpftrace repository in our Linux machine; 10 | 2. We are not cloning it to install bpftrace itself, but to get all the tools under the `tools` folder 11 | 12 | .exercise[ 13 | - Clone the bpftrace repo 14 | ```bash 15 | git clone https://github.com/iovisor/bpftrace.git 16 | cd bpftrace/tools 17 | ``` 18 | ] 19 | -------------------------------------------------------------------------------- /content/bpftrace/524-bpftrace-exercise-tools-tcpretrans.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-exercise-tools-tcpretrans" 3 | weight: 524 4 | class: extra-details 5 | --- 6 | 7 | ## bpftrace hands on: Trace or count TCP retransmits 8 | 9 | - In the bpftrace tools folder, there's a tool called `tcpretrans.bt`; 10 | - TCP wants to make sure that your packet is received with the *guarantee* that all the received bytes will be identical and in the same order as those sent, 11 | this technique is called **positive acknowledgement with re-transmission**; 12 | - What happens when there are many retransmits is that your system can have a significant overhead, then you want to know when a retransmit occurs, `tcpretrans.bt` does just that 13 | - Retransmits are usually a sign of poor network health, and this tool is 14 | useful for their investigation. Unlike using tcpdump, this tool has very 15 | low overhead, as it only traces the retransmit function. It also prints 16 | additional kernel details: the state of the TCP session at the time of the 17 | retransmit. 18 | 19 | -------------------------------------------------------------------------------- /content/bpftrace/525-bpftrace-exercise-tools-tcpretrans-contd.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-exercise-tools-tcpretrans-contd" 3 | weight: 525 4 | class: extra-details 5 | --- 6 | 7 | ## bpftrace hands on: Trace or count TCP retransmits (cont'd) 8 | 9 | .exercise[ 10 | - In the `bpftrace/tools` folder; 11 | - With root permissions; 12 | - Execute the `tcpretrans.bt` tool; 13 | 14 | ```bash 15 | bpftrace tcpretrans.bt 16 | ``` 17 | - Once it's started, the best way to trigger some retransmits is to try to connect to a closed port; 18 | - Try it on a new terminal while leaving `tcpretrans.bt` active! 19 | 20 | ```bash 21 | telnet bpf.sh 9090 22 | ``` 23 | ] 24 | -------------------------------------------------------------------------------- /content/bpftrace/526-bpftrace-oneliner-read-kernel-tracing-vfs.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "bpftrace-oneliners-read-kernel-tracing-vfs" 4 | weight: 526 5 | class: extra-details 6 | --- 7 | 8 | # bpftrace hands on: tracing read bytes using a kretprobe 9 | 10 | - We will use the capability of bpftrace to instrument the `vfs_read` function in the kernel using a `kretprobe`; 11 | - We will create an array called `bytes` that will dump a linear histogram where the arguments are: value, min, max, step. The first argument (retval) of vfs_read() is the return value: the number of bytes read; 12 | 13 | .exercise[ 14 | - Execute this one liner using bpftrace, then let it run for a while then use `Ctrl-C` to dump the results 15 | ```bash 16 | bpftrace -e 'kretprobe:vfs_read { @bytes = lhist(retval, 0, 2000, 200); }' 17 | ``` 18 | ] 19 | 20 | .footnote[.smaller[ 21 | In Linux, all files are accessed through the Virtual Filesystem Switch, or VFS, a layer of code which implements generic filesystem actions and vectors requests to the correct specific code to handle the request. 22 | ]] 23 | 24 | 25 | -------------------------------------------------------------------------------- /content/bpftrace/527-bpftrace-oneliner-read-syscall.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "bpftrace-oneliners-read-syscall" 4 | weight: 527 5 | class: extra-details 6 | --- 7 | 8 | # bpftrace hands on: tracing read bytes using a tracepoint 9 | 10 | - We want to do the same thing we did with the `kretprobe` in the previous exercise 11 | 12 | .exercise[ 13 | - Execute this one liner using bpftrace 14 | ```bash 15 | bpftrace -e 'tracepoint:syscalls:sys_exit_read { @bytes = lhist(args->ret, 0, 2000, 200); }' 16 | ``` 17 | - Let it run for a while then use `Ctrl-C` to dump the results 18 | ] 19 | 20 | **What's the difference?** 21 | While being very powerful (it can trace any kernel function), `kretprobe` approach can't be considered "stable", because internal 22 | kernel functions can change between kernels. On the other hand using a tracepoint is a much more stable approach because tracepoints 23 | are considered as a user facing feature and not an internal one by kernel developers. 24 | Whenever possible use tracepoints instead of kprobe/kretprobe. 25 | 26 | 27 | -------------------------------------------------------------------------------- /content/bpftrace/528-bpftrace-oneliner-uretprobe.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "bpftrace-oneliners-uretprobe" 4 | weight: 528 5 | class: extra-details 6 | --- 7 | 8 | # bpftrace hands on: reading userspace returns 9 | 10 | We have a Go program that prints a random number every second. 11 | ```go 12 | package main 13 | import( 14 | "time" 15 | "fmt" 16 | "math/rand" 17 | ) 18 | func main() { 19 | for { 20 | time.Sleep(time.Second * 1) 21 | fmt.Printf("%d\n", giveMeNumber()) 22 | } 23 | } 24 | func giveMeNumber() int { 25 | return rand.Intn(100) + rand.Intn(900) 26 | } 27 | ``` 28 | We want to get the random number out of it using a bpftrace program. 29 | -------------------------------------------------------------------------------- /content/bpftrace/529-bpftrace-oneliner-uretprobe-contd.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "bpftrace-oneliners-uretprobe-contd" 4 | weight: 529 5 | class: extra-details 6 | --- 7 | 8 | # bpftrace hands on: reading userspace returns 9 | .exercise[ 10 | - Create a file named `main.go` with the code from [previous slide](#bpftrace-oneliners-uretprobe); 11 | - Then, compile it with: 12 | ```bash 13 | go build -o randomnumbers main.go 14 | ``` 15 | - This will create a binary named `randomnumbers` in the current folder; 16 | - Once that is done, we just start the program `./randomnumbers`; 17 | - Now, in a new terminal, we instrument the program using bpftrace and a `uretprobe`: 18 | 19 | ```bash 20 | bpftrace -e \ 21 | 'uretprobe:./randomnumbers:"main.giveMeNumber" 22 | { printf("%d\n", retval) }' 23 | ``` 24 | ] 25 | 26 | .footnote[.smaller[Bonus point! Try to do an `objdump -t randomnumbers | grep -i giveMe`, what do you notice?]] 27 | 28 | -------------------------------------------------------------------------------- /content/bpftrace/590-bpftrace-internals.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "bpftrace-internals" 4 | weight: 590 5 | --- 6 | 7 | # bpftrace: Internals 8 | 9 | .pic[ 10 | ![supported bpf probe types](/img/bpftrace-internals.png) 11 | ] 12 | -------------------------------------------------------------------------------- /content/bpftrace/598-bpftrace-takeaways.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-takeaways" 3 | weight: 598 4 | --- 5 | 6 | # Takeaways 7 | 8 | - There's an higher level language to use eBPF, called `bpftrace`; 9 | - `bpftrace` can be used only for eBPF based tracing; 10 | - It's pretty magic; 11 | - There are a **LOT** of premade tools you can use in the `bpftrace/tools` folder, saves a lot of time; 12 | -------------------------------------------------------------------------------- /content/bpftrace/599-bpftrace-credits.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace-credits" 3 | weight: 599 4 | --- 5 | 6 | # Credits and References 7 | 8 | - [Brendan Gregg's presentation on bpftrace](https://github.com/iovisor/bpf-docs/blob/master/bpftrace_public_template_jun2019.odp) 9 | - [IOVisor's bpftrace reference guide](https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md) 10 | - [IOVisor's bpftrace repository](https://github.com/iovisor/bpftrace) 11 | - [Wikipedia article on TCP](https://en.wikipedia.org/wiki/Transmission_Control_Protocol) 12 | - [IOVisor's bpftrace one liner's tutorial](https://github.com/iovisor/bpftrace/blob/b6c4136fabf2527fc736bc08ee875625156b5431/docs/tutorial_one_liners.md) 13 | -------------------------------------------------------------------------------- /content/bpftrace/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "bpftrace" 3 | weight: 500 4 | class: title 5 | 6 | --- 7 | {{< nav >}} 8 | 9 | -------------------------------------------------------------------------------- /content/introduction/101-introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "introduction-content" 3 | weight: 101 4 | --- 5 | 6 | # Introduction 7 | 8 | - The BSD Packet Filter: A New Architecture for User-level Packet Capture 9 | - Virtual Machine to work efficiently with register based CPUs 10 | - Packet filtering without copying data 11 | 12 | -------------------------------------------------------------------------------- /content/introduction/102-extended-bpf-implementation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "extended-bpf-implementation" 3 | weight: 102 4 | --- 5 | 6 | # The extended BPF implementation (eBPF) 7 | 8 | - Introduced in 2014 by Alexei Starovoitov 9 | - Increased register size from 2 32-bit registers to 10 64-bit registers 10 | - Initially designed to optimize network filters 11 | -------------------------------------------------------------------------------- /content/introduction/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "introduction" 3 | weight: 100 4 | class: title 5 | --- 6 | {{< nav >}} 7 | 8 | -------------------------------------------------------------------------------- /content/kubernetes/710-kubernetes-just-a-container.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "kubernetes-just-a-container" 3 | weight: 710 4 | 5 | --- 6 | 7 | # Approach #1: Just use a container 8 | 9 | - A sidecar container sharing the process namespace; 10 | - You just provide an image with eBPF loader as entrypoint; 11 | - The loader will just load the program and execute it; 12 | - Not extremely generic but does the job! 13 | - A very flexible approach! 14 | 15 | .small[.small[ 16 | ```yaml 17 | apiVersion: v1 18 | kind: Pod 19 | metadata: 20 | name: happy-borg 21 | spec: 22 | shareProcessNamespace: true 23 | containers: 24 | - name: execsnoop 25 | image: calavera/execsnoop 26 | securityContext: 27 | - privileged: true 28 | volumeMounts: 29 | - name: sys # mount the debug filesystem 30 | mountPath: /sys 31 | readOnly: true 32 | - name: headers # mount the kernel headers required by bcc 33 | mountPath: /usr/src 34 | readOnly: true 35 | - name: modules # mount the kernel modules required by bcc 36 | mountPath: /lib/modules 37 | readOnly: true 38 | - name: container doing random work 39 | ... 40 | ``` 41 | ]] 42 | -------------------------------------------------------------------------------- /content/kubernetes/711-kubernetes-kubectl-trace.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "kubernetes-kubectl-trace" 3 | weight: 711 4 | --- 5 | 6 | # Approach #2: kubectl-trace 7 | 8 | - It's basically [*bpftrace*](#bpftrace), but for the kubectl! 9 | - It's on GitHub [iovisor/kubectl-trace](https://github.com/iovisor/kubectl-trace) 10 | 11 | .pic[ 12 | ![img/kubernetes-kubectl-trace.png](img/kubernetes-kubectl-trace.png) 13 | ] 14 | 15 | 16 | -------------------------------------------------------------------------------- /content/kubernetes/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "kubernetes" 3 | weight: 700 4 | class: title 5 | 6 | --- 7 | {{< nav >}} 8 | 9 | -------------------------------------------------------------------------------- /content/networking/1001-networking-intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-intro" 3 | weight: 1001 4 | 5 | --- 6 | 7 | # eBPF and Linux Networking 8 | 9 | **Main use cases** 10 | 11 | - Retrospective analysis of network traffic captured on a live system, using the pcap format for example; 12 | - Live packet filtering, e.g: allow only UDP traffic and discard anything else; 13 | - Live observation of a filtered set of packets flowing into a live system; 14 | 15 | 16 | **At different levels** 17 | 18 | - cBPF packet filtering 19 | - Raw packet filtering (`BPF_PROG_TYPE_SOCKET_FILTER`) 20 | - Traffic control 21 | - XDP 22 | 23 | -------------------------------------------------------------------------------- /content/networking/1002-networking-tcpdump.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-tcpdump" 3 | weight: 1002 4 | 5 | --- 6 | 7 | # cBPF and packet filtering 8 | 9 | - Packet filtering is done using an accumulator on which filters are applied, the classic BPF way; 10 | - One of the most popular use cases for it is `tcpdump`; 11 | - It doesn't support the use of maps; 12 | 13 | **Tcpdump** 14 | 15 | - Probably the most known use cases for live packets observation; 16 | - It is implemented as a frontend for `libpcap`; 17 | - Allows to define high level filtering expression that are then converted to a BPF filtering expression; 18 | - Tcpdump can dump the used BPF for user inspection; 19 | - Can read from an existing pcap file and filter on it 20 | 21 | -------------------------------------------------------------------------------- /content/networking/1003-networking-tcpdump-exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-tcpdump-exercise" 3 | weight: 1003 4 | 5 | --- 6 | 7 | # hands on: Tcpdump packet filtering 8 | 9 | .exercise[ 10 | In a new terminal, execute `tcpdump` with a filter and use the `-d` option to dump the generated BPF assembly. 11 | 12 | ```bash 13 | tcpdump -d 'ip and tcp port 8080' 14 | ``` 15 | What do you see? Anything noteworthy? 16 | ] 17 | 18 | -------------------------------------------------------------------------------- /content/networking/1004-networking-tcpdump-exercise-result.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-tcpdump-exercise-result" 3 | weight: 1004 4 | 5 | --- 6 | 7 | # tcpdump hands on: What is that stuff? 8 | 9 | .pic[ 10 | ![tcpdump explanation](/img/tcpdump.png) 11 | ] 12 | 13 | -------------------------------------------------------------------------------- /content/networking/1005-networking-raw-sockets.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-raw-packets" 3 | weight: 1005 4 | 5 | --- 6 | 7 | # Raw packets filtering 8 | 9 | - Attach a BPF program to a socket 10 | - All the packets received by it will be to the program as an `sk_buff` struct 11 | - The program can make the decision on whether to discard or allow them based on its logic 12 | 13 | 14 | Here's an example, the program type is given by the `SEC("socket")` definition that gets translated to `BPF_PROG_TYPE_SOCKET_FILTER`. 15 | 16 | .small[ 17 | ```c 18 | SEC("socket") 19 | int socket_prog(struct __sk_buff *skb) { 20 | int proto = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol)); 21 | int one = 1; 22 | int *el = bpf_map_lookup_elem(&countmap, &proto); 23 | if (el) { 24 | (*el)++; 25 | } else { 26 | el = &one; 27 | } 28 | bpf_map_update_elem(&countmap, &proto, el, BPF_ANY); 29 | return 0; 30 | } 31 | ``` 32 | ] 33 | -------------------------------------------------------------------------------- /content/networking/1006-networking-traffic-control.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-traffic-control" 3 | weight: 1006 4 | 5 | --- 6 | 7 | # Traffic Control (tc) and eBPF 8 | 9 | - tc is the kernel packet scheduling subsystem; 10 | - It's made of mechanisms and queuing systems that decide how packet flows and are accepted into the system; 11 | - It has a classifier that can use a bpf program to make the decisions, called `cls_bpf`; 12 | 13 | Among tc use cases there are: 14 | 15 | - Prioritize certain kinds of packets 16 | - Drop specific kind of packet 17 | - Bandwidth distribution 18 | 19 | 20 | -------------------------------------------------------------------------------- /content/networking/1007-networking-traffic-control-clsbpf.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-traffic-control" 3 | weight: 1007 4 | 5 | --- 6 | 7 | # Traffic Control cls_bpf hook points 8 | 9 | - cls_bpf can hook in ingress and egress 10 | - that means that you can manipulate both packets your machine receives and packets it sends! 11 | - programs receive an `sk_buff` 12 | 13 | Here's a diagram showing the interactions: 14 | 15 | .pic[![cls_bpf interactions](/img/tc-flow-bpf-cls.png)] 16 | -------------------------------------------------------------------------------- /content/networking/1008-networking-tc-example.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-tc-example" 3 | weight: 1008 4 | --- 5 | 6 | # Example: TC program to drop all TCP packets 7 | 8 | .small[.small[ 9 | ```c 10 | SEC("classifier") 11 | static inline int classification(struct __sk_buff *skb) { 12 | void *data_end = (void *)(long)skb->data_end; 13 | void *data = (void *)(long)skb->data; 14 | struct ethhdr *eth = data; 15 | 16 | __u16 h_proto; 17 | __u64 nh_off = 0; 18 | nh_off = sizeof(*eth); 19 | 20 | if (data + nh_off > data_end) { 21 | return TC_ACT_OK; 22 | } 23 | 24 | h_proto = eth->h_proto; 25 | 26 | if (h_proto != bpf_htons(ETH_P_IP)) { 27 | return TC_ACT_OK; 28 | } 29 | 30 | struct iphdr *iph = data + nh_off; 31 | 32 | if (iph + 1 > data_end) { 33 | return TC_ACT_OK; 34 | } 35 | 36 | if (iph->protocol -= IPPROTO_TCP) { 37 | return TC_ACT_SHOT 38 | } 39 | 40 | return TC_ACT_OK; 41 | } 42 | ``` 43 | ]] 44 | 45 | .small[ 46 | The classifier program is added to the qdisc using `tc`: 47 | 48 | ``` 49 | tc filter add dev eth0 ingress bpf obj classifier.o flowid 0: 50 | ``` 51 | ] 52 | -------------------------------------------------------------------------------- /content/networking/1028-networking-xdp.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-xdp" 3 | weight: 1029 4 | --- 5 | 6 | # Xpress Data Path 7 | 8 | - Programs are of type `BPF_PROG_TYPE_XDP` 9 | - There are three operation modes: 10 | - *Native:* the network card driver supports XDP, code runs on the driver receive path; 11 | - *Offloaded:* the network card hardware supports XDP, the nic CPU will execute the logic; 12 | - *Generic:* It's provided as a test mode for developers it's for testing xdp programs without having the proper hardware; 13 | - Once packets are processed, XDP will return one of its possible codes: 14 | - *XDP_DROP*: drop the packet; 15 | - *XDP_TX*: forward the packet; 16 | - *XDP_REDIRECT*: similar to TX but forward to another nic or map of type CPU map; 17 | - *XDP_PASS*: allow the packet 18 | -------------------------------------------------------------------------------- /content/networking/1029-networking-xdp-tc-differences.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-xdp-tc-differences" 3 | weight: 1029 4 | --- 5 | 6 | # Differences between TC and XDP 7 | 8 | - XDP programs are executed earlier in the ingress data path, before entering in the main kernel network stack; 9 | - Program does not have access to a Socket buffer struct sk_buff like with tc; 10 | - XDP programs instead take a different structure called xdp_buff that is an eager representation of the packet without metadata; 11 | 12 | **All this comes with advantages and disadvantages**: 13 | 14 | Being executed even before the kernel code, XDP programs can drop packets in a very efficient way. Compared to tc programs, XDP programs can only be attached to traffic in ingress to the system. 15 | -------------------------------------------------------------------------------- /content/networking/1030-networking-xdp-interactions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-xdp-interactions" 3 | weight: 1030 4 | --- 5 | 6 | # XDP packets processor 7 | 8 | .footnote[.smaller[ 9 | - It executes BPF programs for XDP packets 10 | - Coordinates the interaction between them and the network stack 11 | - It ensures that packets are read and writeable and allows to attach post processing verdicts in the form of packet processor actions 12 | - The illustrated return codes before, are its return actions! 13 | 14 | ]] 15 | .pic[ 16 | ![xdp packets processor](/img/xdp-interaction-diagram.png) 17 | ] 18 | 19 | -------------------------------------------------------------------------------- /content/networking/1031-networking-xdp-example.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking-xdp-example" 3 | weight: 1031 4 | --- 5 | 6 | # Example: XDP program to drop all TCP packets 7 | 8 | .small[ 9 | ```c 10 | SEC("mysection") 11 | int myprogram(struct xdp_md *ctx) { 12 | int ipsize = 0; 13 | void *data = (void *)(long)ctx->data; 14 | void *data_end = (void *)(long)ctx->data_end; 15 | struct ethhdr *eth = data; 16 | struct iphdr *ip; 17 | 18 | ipsize = sizeof(*eth); 19 | ip = data + ipsize; 20 | ipsize += sizeof(struct iphdr); 21 | if (data + ipsize > data_end) { 22 | return XDP_DROP; 23 | } 24 | 25 | if (ip->protocol == IPPROTO_TCP) { 26 | return XDP_DROP; 27 | } 28 | 29 | return XDP_PASS; 30 | } 31 | ``` 32 | 33 | It can be loaded on any interface using: 34 | 35 | ``` 36 | ip link set dev enp0s8 xdp obj udp.o sec mysection 37 | ```] 38 | -------------------------------------------------------------------------------- /content/networking/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "networking" 3 | weight: 1000 4 | class: title 5 | 6 | --- 7 | {{< nav >}} 8 | 9 | -------------------------------------------------------------------------------- /content/security/1101-security-seccomp.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "security-seccomp" 3 | weight: 1101 4 | class: extra-details 5 | --- 6 | 7 | # Seccomp 8 | 9 | - Stands for Secure Computing; 10 | - Implements a filtering backend based on cBPF 11 | - You can write a BPF program hat filters the execution of any syscall by allowing/disallowing the ones you want based on your logic; 12 | 13 | Here's the seccomp data structure for filters as from `linux/seccomp.h` 14 | 15 | ```c 16 | struct seccomp_data { 17 | int nr; 18 | __u32 arch; 19 | __u64 instruction_pointer; 20 | __u64 args[6]; 21 | }; 22 | ``` 23 | 24 | Allows to filter based on: the system call, its arguments or a combination of them. 25 | 26 | -------------------------------------------------------------------------------- /content/security/1102-security-lsm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "security-lsm" 3 | weight: 1102 4 | class: extra-details 5 | --- 6 | 7 | # LSM Hooks 8 | 9 | - The Linux security modules (LSM) framework, has a set of hooks to control the execution of (e)BPF programs, 10 | - Allows to create a fine-grained set of privileges around them when using a module that implements BPF hooks support 11 | - Actually implemented by Landlock and SELinux 12 | - The only in kernel tree implementation is SELinux 13 | - It's based on the concept of hook calls instead of syscalls 14 | -------------------------------------------------------------------------------- /content/security/1103-security-seccomp-exercise.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "security-seccomp-exercise" 3 | weight: 1103 4 | class: extra-details 5 | --- 6 | 7 | ## hands on: Seccomp filters using bpf programs 8 | 9 | .exercise[ 10 | - Clone the exercise repository and cd into it 11 | ```bash 12 | git clone https://gist.github.com/fntlnz/08ae20befb91befd9a53cd91cdc6d507 seccomp-exercise 13 | cd seccomp-exercise 14 | ``` 15 | 16 | - After following the instructions in `README.md`, what do you notice? 17 | ] 18 | -------------------------------------------------------------------------------- /content/security/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "security" 3 | weight: 1100 4 | class: title 5 | --- 6 | {{< nav >}} 7 | 8 | -------------------------------------------------------------------------------- /environment/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .vagrant/ 3 | -------------------------------------------------------------------------------- /environment/README.md: -------------------------------------------------------------------------------- 1 | # BPF Workshop Environment 2 | 3 | **Requirements** 4 | 5 | - [Vagrant](https://www.vagrantup.com/downloads.html) 6 | - [Virtualbox](https://www.virtualbox.org/) 7 | 8 | 9 | **Installed tools** 10 | 11 | - git 12 | - wget 13 | - vim 14 | - gcc 15 | - clang 16 | - bpftrace 17 | - bcc 18 | - go 19 | -------------------------------------------------------------------------------- /environment/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | VAGRANTFILE_API_VERSION = "2" 5 | 6 | $bootstrap=< 2 | 8 | -------------------------------------------------------------------------------- /themes/workshop/layouts/partials/header.html: -------------------------------------------------------------------------------- 1 | 2 | {{ .Title }} 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /themes/workshop/layouts/partials/slides.html: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /themes/workshop/layouts/shortcodes/nav.html: -------------------------------------------------------------------------------- 1 | {{ if not .Page.Title }} 2 | .red[error rendering the nav menu], add 3 | 4 | ``` 5 | title: "your-id" 6 | ``` 7 | To the page. 8 | It should match what the identifier you did put in the menu in the config file! 9 | 10 | {{ end }} 11 | 12 | {{ $currentPage := .Page.Title }} 13 | 14 | {{ $navTitle := "Title not provided" }} 15 | {{ range .Site.Menus.main.ByWeight }} 16 | {{ if eq .Identifier $currentPage}} 17 | {{ if .Title }} 18 | {{ $navTitle = .Title }} 19 | {{ end }} 20 | {{ end }} 21 | {{ end }} 22 | 23 | {{ $navTitle }} 24 | {{ $previous := "" }} 25 | {{ $next := "" }} 26 | 27 | {{ $previousIteration := "" }} 28 | {{ $stop := false }} 29 | {{ range .Site.Menus.main.ByWeight }} 30 | {{ if eq $currentPage .Identifier }} 31 | {{ $previous = $previousIteration }} 32 | {{ end }} 33 | 34 | {{ if eq $previousIteration $currentPage }} 35 | {{ $next = .Identifier }} 36 | {{ end }} 37 | 38 | {{ $previousIteration = .Identifier }} 39 | {{ end }} 40 | 41 | .nav[ [Previous section](#{{$previous}}) 42 | | 43 | [Back to table of contents](#toc) 44 | | 45 | [Next section](#{{$next}}) 46 | ] 47 | -------------------------------------------------------------------------------- /themes/workshop/layouts/shortcodes/toc.html: -------------------------------------------------------------------------------- 1 | {{ range .Site.Menus.main.ByWeight }}- [{{ .Title }}](#{{.Identifier}}) 2 | {{ end }} 3 | 4 | 5 | -------------------------------------------------------------------------------- /themes/workshop/static/images/extra-details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpftools/bpf-workshop/95cf57a16a1afc0798bfa63a4c7b63c0dc43a807/themes/workshop/static/images/extra-details.png -------------------------------------------------------------------------------- /themes/workshop/static/images/keyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpftools/bpf-workshop/95cf57a16a1afc0798bfa63a4c7b63c0dc43a807/themes/workshop/static/images/keyboard.png -------------------------------------------------------------------------------- /themes/workshop/static/images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bpftools/bpf-workshop/95cf57a16a1afc0798bfa63a4c7b63c0dc43a807/themes/workshop/static/images/warning.png -------------------------------------------------------------------------------- /themes/workshop/static/workshop.css: -------------------------------------------------------------------------------- 1 | /* Originally coming from: https://github.com/jpetazzo/container.training/blob/master/slides/workshop.css */ 2 | 3 | @import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic); 4 | @import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic); 5 | 6 | @import url('https://fonts.googleapis.com/css?family=Inconsolata:400,700'); 7 | @import url('https://fonts.googleapis.com/css?family=Open+Sans'); 8 | 9 | /* Fonts! Sizes! And a bit of color. */ 10 | .remark-slide-content { 11 | font-family: 'Droid Serif'; 12 | font-size: 25px !important; 13 | } 14 | 15 | .emoji { 16 | font-family: 'EmojiOne Color'; 17 | } 18 | 19 | h1, h2, h3, h4, h5, h6 { 20 | font-family: 'Droid Serif'; 21 | font-weight: bold; 22 | font-size: 45px !important; 23 | margin-top: 0.5em; 24 | } 25 | 26 | code { 27 | font-family: 'Inconsolata'; 28 | font-size: 110%; 29 | background-color: #ccc; 30 | } 31 | code.remark-code { 32 | font-size: 100%; 33 | } 34 | .exercise ul li code.remark-code.hljs.bash { 35 | padding: 0; 36 | } 37 | 38 | /* For print! Borrowed from https://github.com/gnab/remark/issues/50 */ 39 | @page { 40 | size: 1210px 681px; 41 | margin: 0; 42 | } 43 | 44 | @media print { 45 | .remark-slide-scaler { 46 | width: 100% !important; 47 | height: 100% !important; 48 | transform: scale(1) !important; 49 | top: 0 !important; 50 | left: 0 !important; 51 | } 52 | } 53 | 54 | /* Don't change things below this unless you know what you're doing! */ 55 | 56 | /* put slide numbers in top-right corner instead of bottom-right */ 57 | div.remark-slide-number { 58 | top: 6px; 59 | left: unset; 60 | bottom: unset; 61 | right: 6px; 62 | } 63 | 64 | .debug { 65 | font-family: monospace; 66 | position: absolute; 67 | left: 0px; 68 | right: 0px; 69 | bottom: 0px; 70 | color: white; 71 | background-color: black; 72 | opacity: 0; 73 | } 74 | .debug a { 75 | color: white; 76 | } 77 | .debug:hover { 78 | opacity: 1; 79 | } 80 | 81 | a { 82 | text-decoration: none; 83 | color: blue; 84 | } 85 | 86 | .remark-slide-content { padding: 1em 2.5em 1em 2.5em; } 87 | 88 | .footnote { 89 | position: absolute; 90 | bottom: 1em; 91 | } 92 | span.footnote { 93 | bottom: 2em; 94 | } 95 | 96 | .footnote .smaller { 97 | font-size: 0.7em; 98 | } 99 | 100 | .red { color: #fa0000; } 101 | .gray { color: #ccc; } 102 | .small { font-size: 70%; } 103 | .big { font-size: 140%; } 104 | .underline { text-decoration: underline; } 105 | .strike { text-decoration: line-through; } 106 | 107 | /* On pic slides, zoom images as big as possible */ 108 | div.pic { 109 | padding: 0; 110 | vertical-align: middle; 111 | } 112 | div.pic p { 113 | margin: 0; 114 | } 115 | div.pic img { 116 | display: block; 117 | margin: auto; 118 | max-width: 1210px; 119 | max-height: 550px; 120 | } 121 | div.pic h1, div.pic h2, div.title h1, div.title h2 { 122 | text-align: center; 123 | } 124 | 125 | /* Center images that are on title slides */ 126 | div.title img { 127 | display: block; 128 | margin: auto; 129 | max-width: 1210px; 130 | max-height: 420px; /* Arbitrary value to have so space for the title */ 131 | } 132 | div.title { 133 | vertical-align: middle; 134 | } 135 | div.title > p:first-child { 136 | text-align: center; 137 | font-size: 300%; 138 | } 139 | 140 | div.pic span.interstitial img { 141 | width: 100%; 142 | max-height: unset; 143 | max-width: unset; 144 | } 145 | 146 | /* "Normal" images (not on title or pic slides) shouldn't be too big */ 147 | div img { 148 | max-width: 1210px; 149 | max-height: 250px; 150 | } 151 | 152 | .nav { 153 | text-align: center; 154 | position: absolute; 155 | left: 0; 156 | right: 0; 157 | bottom: 25px; 158 | font-size: 150%; 159 | } 160 | 161 | .warning { 162 | background-image: url("images/warning.png"); 163 | background-size: 1.5em; 164 | padding-left: 2em; 165 | padding-top: 0.2em; 166 | padding-bottom: 0.2em; 167 | background-repeat: no-repeat; 168 | background-position: left; 169 | } 170 | .exercise { 171 | background-color: #eee; 172 | background-image: url("images/keyboard.png"); 173 | background-size: 1.4em; 174 | background-repeat: no-repeat; 175 | background-position: 0.2em 0.2em; 176 | border: 2px dotted black; 177 | } 178 | .exercise:before { 179 | content: "Hands-on exercise"; 180 | margin-left: 1.8em; 181 | } 182 | 183 | li p { line-height: 1.25em; } 184 | 185 | div.extra-details { 186 | background-image: url("images/extra-details.png"); 187 | background-position: 0.5% 1%; 188 | background-size: 4%; 189 | } 190 | 191 | /* This is used only for the history slide (the only table in this doc) */ 192 | td { 193 | padding: 0.1em 0.5em; 194 | background: #eee; 195 | } 196 | -------------------------------------------------------------------------------- /themes/workshop/theme.toml: -------------------------------------------------------------------------------- 1 | name = "workshop" 2 | description = "workshop theme" 3 | --------------------------------------------------------------------------------