├── .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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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[]
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 | 
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 |
--------------------------------------------------------------------------------