├── .gitignore ├── L3AF_KFaaS.pdf ├── CODEOWNERS ├── images ├── L3AF_dev_env.png ├── L3AF_platform.png ├── L3AF_eBPF_chaining.png ├── dashboard_preview.png ├── logos │ ├── Color │ │ ├── L3AF_logo.ai │ │ ├── L3AF_logo.png │ │ └── L3AF_logo.svg │ ├── Black │ │ ├── L3AF_logo_Black.ai │ │ ├── L3AF_logo_Black.png │ │ └── L3AF_logo_Black.svg │ └── White │ │ ├── L3AF_logo_White.ai │ │ ├── L3AF_logo_White.png │ │ └── L3AF_logo_White.svg ├── L3AF_decouple_chaining.png └── L3AF_xdp_dispatcher_chaining.png ├── dev_environment ├── e2e_test │ ├── restart.json │ ├── exp_output_nil.json │ ├── del_tm_payload.json │ ├── del_ipfix_payload.json │ ├── del_without_chaining_payload.json │ ├── del_payload.json │ ├── prep_env.sh │ ├── gen1.sh │ ├── gen2.sh │ ├── add_without_chaining_payload.json │ ├── upd_without_chaining_payload.json │ ├── add_tm_payload.json │ ├── exp_output_7.json │ ├── add_payload.json │ ├── upd_payload.json │ ├── exp_output_5.json │ ├── exp_output_6.json │ ├── exp_output_1.json │ ├── exp_output_2.json │ ├── exp_output_4.json │ ├── exp_output_3.json │ └── test_suite.sh ├── cfg │ ├── restart.json │ ├── grafana │ │ ├── provisioning │ │ │ ├── datasources │ │ │ │ └── l3af.yaml │ │ │ └── dashboards │ │ │ │ └── l3af.yaml │ │ └── dashboards │ │ │ ├── l3af_rate_limiting.json │ │ │ ├── l3af_connection_limiting.json │ │ │ └── l3af_ebpf_programs.json │ ├── delete_payload.json │ ├── otel-collector-config.yml │ ├── prometheus.yml │ ├── l3afd.cfg │ ├── traffic_mirroring_payload.json │ └── payload.json ├── config.yaml ├── code │ └── web-server.go ├── generate_payload.sh ├── start_test_servers.sh ├── setup_dev_env_linux_vm.md ├── provision.sh ├── README.md ├── Vagrantfile └── setup_linux_dev_env.sh ├── README.md ├── LICENSE └── discussions ├── secure_web_api.md ├── chaining_enhancements.md └── prog_repo.md /.gitignore: -------------------------------------------------------------------------------- 1 | /dev_environment/.vagrant 2 | /dev_environment/*.log 3 | -------------------------------------------------------------------------------- /L3AF_KFaaS.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/L3AF_KFaaS.pdf -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Default Code Owners 2 | 3 | * @jniesz @sanfern @charleskbliu0 @dalalkaran @pmoroney 4 | -------------------------------------------------------------------------------- /images/L3AF_dev_env.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/L3AF_dev_env.png -------------------------------------------------------------------------------- /images/L3AF_platform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/L3AF_platform.png -------------------------------------------------------------------------------- /dev_environment/e2e_test/restart.json: -------------------------------------------------------------------------------- 1 | { 2 | "hostname": "l3af-test-host", 3 | "version": "v2.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /dev_environment/cfg/restart.json: -------------------------------------------------------------------------------- 1 | { 2 | "hostname": "l3af-test-host", 3 | "version": "v2.0.0" 4 | } 5 | 6 | -------------------------------------------------------------------------------- /images/L3AF_eBPF_chaining.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/L3AF_eBPF_chaining.png -------------------------------------------------------------------------------- /images/dashboard_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/dashboard_preview.png -------------------------------------------------------------------------------- /images/logos/Color/L3AF_logo.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/logos/Color/L3AF_logo.ai -------------------------------------------------------------------------------- /images/logos/Color/L3AF_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/logos/Color/L3AF_logo.png -------------------------------------------------------------------------------- /images/L3AF_decouple_chaining.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/L3AF_decouple_chaining.png -------------------------------------------------------------------------------- /images/logos/Black/L3AF_logo_Black.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/logos/Black/L3AF_logo_Black.ai -------------------------------------------------------------------------------- /images/logos/White/L3AF_logo_White.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/logos/White/L3AF_logo_White.ai -------------------------------------------------------------------------------- /images/L3AF_xdp_dispatcher_chaining.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/L3AF_xdp_dispatcher_chaining.png -------------------------------------------------------------------------------- /images/logos/Black/L3AF_logo_Black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/logos/Black/L3AF_logo_Black.png -------------------------------------------------------------------------------- /images/logos/White/L3AF_logo_White.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l3af-project/l3af-arch/HEAD/images/logos/White/L3AF_logo_White.png -------------------------------------------------------------------------------- /dev_environment/cfg/grafana/provisioning/datasources/l3af.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: l3af 5 | isDefault: true 6 | type: prometheus 7 | url: http://localhost:9090 8 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/exp_output_nil.json: -------------------------------------------------------------------------------- 1 | { 2 | "host_name": "l3af-test-host", 3 | "iface": "ibpfbr", 4 | "ipv4_address": "192.168.15.80", 5 | "bpf_programs": { 6 | "xdp_ingress": null, 7 | "tc_ingress": null, 8 | "tc_egress": null, 9 | "probes": null 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dev_environment/config.yaml: -------------------------------------------------------------------------------- 1 | configs: 2 | host_http_port1: '18080' 3 | host_http_port2: '18081' 4 | host_grafana_port: '33000' 5 | host_prometheus_port: '39090' 6 | host_l3af_config_port: '37080' 7 | host_l3af_debug_port: '38899' 8 | host_l3afd_code_dir: '/code/l3afd' 9 | traffic_mirroring: 'false' 10 | otel_collector: 'false' 11 | host_distro_codename: 'jammy' 12 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/del_tm_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name": "l3af-test-host", 4 | "iface": "ibpfbr", 5 | "ipv4_address": "192.168.15.80", 6 | "bpf_programs": { 7 | "xdp_ingress": null, 8 | "tc_ingress": [ 9 | "traffic-mirroring" 10 | ], 11 | "tc_egress": [ 12 | "traffic-mirroring" 13 | ] 14 | } 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/del_ipfix_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name": "l3af-test-host", 4 | "iface": "ibpfbr", 5 | "ipv4_address": "192.168.15.80", 6 | "bpf_programs": { 7 | "xdp_ingress": null, 8 | "tc_ingress": [ 9 | "ipfix-flow-exporter" 10 | ], 11 | "tc_egress": [ 12 | "ipfix-flow-exporter" 13 | ] 14 | } 15 | } 16 | ] 17 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/del_without_chaining_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name": "l3af-test-host", 4 | "iface": "ibpfbr", 5 | "ipv4_address": "192.168.15.80", 6 | "bpf_programs": { 7 | "xdp_ingress": [ 8 | "ratelimiting" 9 | ], 10 | "tc_ingress": [ 11 | "ipfix-flow-exporter" 12 | ], 13 | "tc_egress": [ 14 | "ipfix-flow-exporter" 15 | ] 16 | } 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /dev_environment/code/web-server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | var port int 11 | 12 | func init() { 13 | flag.IntVar(&port, "port", 8080, "port for this server") 14 | flag.Parse() 15 | } 16 | 17 | func handler(w http.ResponseWriter, r *http.Request) { 18 | fmt.Fprintf(w, "Hello to %q from port %d\n", r.RemoteAddr, port) 19 | } 20 | 21 | func main() { 22 | http.HandleFunc("/", handler) 23 | log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) 24 | } 25 | -------------------------------------------------------------------------------- /dev_environment/cfg/delete_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name": "l3af-local-test", 4 | "iface": "enp0s3", 5 | "ipv4_address": "192.168.105.2", 6 | "bpf_programs": { 7 | "xdp_ingress": [ 8 | "ratelimiting", 9 | "connection-limit" 10 | ], 11 | "tc_ingress": [ 12 | "ipfix-flow-exporter" 13 | ], 14 | "tc_egress": [ 15 | "ipfix-flow-exporter" 16 | ] 17 | } 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/del_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name": "l3af-test-host", 4 | "iface": "ibpfbr", 5 | "ipv4_address": "192.168.15.80", 6 | "bpf_programs": { 7 | "xdp_ingress": [ 8 | "ratelimiting", 9 | "connection-limit" 10 | ], 11 | "tc_ingress": [ 12 | "ipfix-flow-exporter", 13 | "traffic-mirroring" 14 | ], 15 | "tc_egress": [ 16 | "ipfix-flow-exporter", 17 | "traffic-mirroring" 18 | ] 19 | } 20 | } 21 | ] 22 | -------------------------------------------------------------------------------- /dev_environment/generate_payload.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ $# -ge 1 ] && [ "$1" == "-i" ]; then 4 | shift; 5 | echo "This script will change only hostname & interface name if you want more sophisticated configuration Please change payload files manually" 6 | hm=$(hostname) 7 | find ./cfg -type f -name "*.json" -exec sed -i "s/l3af-local-test/$hm/g" {} + 8 | find ./e2e_test -type f -name "*.json" -exec sed -i "s/l3af-test-host/$hm/g" {} + 9 | find ./cfg -type f -name "*.json" -exec sed -i "s/enp0s3/$1/g" {} + 10 | find ./e2e_test -type f -name "*.json" -exec sed -i "s/ibpfbr/$1/g" {} + 11 | else 12 | echo "To run the script: " 13 | echo " ./generate_payload.sh -i " 14 | fi 15 | 16 | -------------------------------------------------------------------------------- /dev_environment/start_test_servers.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eux 3 | 4 | # Start the test web servers 5 | if [ $# -ge 1 ] && [ "$1" == "--ci-build" ]; then 6 | /usr/local/go/bin/go run /root/l3af-arch/dev_environment/code/web-server.go -port 8080 > server1.log 2>&1 & 7 | /usr/local/go/bin/go run /root/l3af-arch/dev_environment/code/web-server.go -port 8081 > server2.log 2>&1 & 8 | elif [ $# -ge 1 ] && [ "$1" == "--curdir" ]; then 9 | /usr/local/go/bin/go run ./code/web-server.go -port 8080 & 10 | /usr/local/go/bin/go run ./code/web-server.go -port 8081 & 11 | else 12 | /usr/local/go/bin/go run /vagrant/code/web-server.go -port 8080 & 13 | /usr/local/go/bin/go run /vagrant/code/web-server.go -port 8081 & 14 | fi 15 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/prep_env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ip netns add bpf 3 | ip link add ibpf type veth peer name ibpfbr 4 | ip link set ibpf netns bpf 5 | ip addr add 192.168.15.80/24 dev ibpfbr 6 | ip -n bpf addr add 192.168.15.1/24 dev ibpf 7 | ip -n bpf link set ibpf up 8 | ip -n bpf link set lo up 9 | ip link set ibpfbr up 10 | modprobe fou 11 | ip fou add port 6080 gue 12 | ip fou add port 6081 gue 13 | ip link add name gue1 type ipip remote 127.0.0.1 local 192.168.15.80 ttl 255 encap gue encap-sport 6080 encap-dport 6081 encap-csum encap-remcsum 14 | ip link add name gue2 type ipip remote 192.168.15.80 local 127.0.0.1 ttl 255 encap gue encap-sport 6081 encap-dport 6080 encap-csum encap-remcsum 15 | ip link set dev gue1 up 16 | ip link set dev gue2 up 17 | -------------------------------------------------------------------------------- /dev_environment/cfg/otel-collector-config.yml: -------------------------------------------------------------------------------- 1 | receivers: 2 | prometheus: 3 | config: 4 | scrape_configs: 5 | - job_name: 'otelcol' 6 | scrape_interval: 5s 7 | static_configs: 8 | - targets: ['0.0.0.0:8888'] 9 | - job_name: 'node' 10 | scrape_interval: 5s 11 | static_configs: 12 | - targets: ['localhost:9100'] 13 | - job_name: 'l3af' 14 | scrape_interval: 5s 15 | static_configs: 16 | - targets: ['localhost:8898'] 17 | 18 | processors: 19 | batch: 20 | 21 | exporters: 22 | prometheusremotewrite: 23 | endpoint: # Update the endpoint field with your desired remote backend 24 | 25 | service: 26 | pipelines: 27 | metrics: 28 | receivers: [prometheus] 29 | processors: [batch] 30 | exporters: [prometheusremotewrite] 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # l3af-arch 2 | 3 | L3AF Architecture Documentation and Discussion 4 | 5 | ## Documentation 6 | 7 | - [Release process](https://github.com/l3af-project/governance/blob/main/docs/RELEASE_PROCESS.md) 8 | - [L3AF Website](https://l3af.io/): Project landing page 9 | - [Code](https://github.com/l3af-project): Source Code 10 | - [Contributing](https://github.com/l3af-project/l3afd/blob/main/docs/CONTRIBUTING.md): Contributor Guide 11 | - [Wiki](https://wiki.lfnetworking.org/x/8AADAw): Meeting notes and project team resources/updates 12 | - [Mail](main@lists.l3af.io): Connect here by mail 13 | 14 | ## Join the L3AF Community 15 | - Start by joining the community on Slack: [l3afworkspace.slack.com](https://join.slack.com/t/l3afworkspace/shared_invite/zt-1s59fv9tx-Gu4ON9K2_i15srGfmOZigg) 16 | - Ask your targeted questions directly on the [GitHub Discussions page](https://github.com/l3af-project/l3af-arch/discussions) 17 | 18 | -------------------------------------------------------------------------------- /dev_environment/cfg/grafana/provisioning/dashboards/l3af.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | # an unique provider name. Required 5 | - name: 'l3af' 6 | # Org id. Default to 1 7 | orgId: 1 8 | # name of the dashboard folder. 9 | folder: 'l3af' 10 | # folder UID. will be automatically generated if not specified 11 | folderUid: '' 12 | # provider type. Default to 'file' 13 | type: file 14 | # disable dashboard deletion 15 | disableDeletion: false 16 | # how often Grafana will scan for changed dashboards 17 | updateIntervalSeconds: 10 18 | # allow updating provisioned dashboards from the UI 19 | allowUiUpdates: false 20 | options: 21 | # path to dashboard files on disk. Required when using the 'file' type 22 | path: /var/lib/grafana/dashboards 23 | # use folder names from filesystem to create folders in Grafana 24 | foldersFromFilesStructure: true 25 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/gen1.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -rf /var/l3afd/l3af-config.json 4 | curl -X POST http://localhost:7080/l3af/configs/v1/add -d "@add_payload.json" 5 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_1.json 6 | echo >> exp_output_1.json 7 | 8 | curl -X POST http://localhost:7080/l3af/configs/v1/update -d "@upd_payload.json" 9 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_2.json 10 | echo >> exp_output_2.json 11 | 12 | curl -X POST http://localhost:7080/l3af/configs/v1/add -d "@add_tm_payload.json" 13 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_3.json 14 | echo >> exp_output_3.json 15 | 16 | curl -X POST http://localhost:7080/l3af/configs/v1/delete -d "@del_ipfix_payload.json" 17 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_4.json 18 | echo >> exp_output_4.json 19 | 20 | curl -X POST http://localhost:7080/l3af/configs/v1/delete -d "@del_payload.json" 21 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_nil.json 22 | echo >> exp_output_nil.json 23 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/gen2.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -rf /var/l3afd/l3af-config.json 4 | curl -X POST http://localhost:7080/l3af/configs/v1/add -d "@add_without_chaining_payload.json" 5 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_5.json 6 | echo >> exp_output_5.json 7 | 8 | curl -X POST http://localhost:7080/l3af/configs/v1/update -d "@upd_without_chaining_payload.json" 9 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_6.json 10 | echo >> exp_output_6.json 11 | 12 | curl -X POST http://localhost:7080/l3af/configs/v1/delete -d "@del_without_chaining_payload.json" 13 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_nil.json 14 | echo >> exp_output_nil.json 15 | 16 | curl -X POST http://localhost:7080/l3af/configs/v1/add -d "@add_tm_payload.json" 17 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_7.json 18 | echo >> exp_output_7.json 19 | 20 | curl -X POST http://localhost:7080/l3af/configs/v1/delete -d "@del_tm_payload.json" 21 | curl http://localhost:7080/l3af/configs/v1/ibpfbr > exp_output_nil.json 22 | echo >> exp_output_nil.json 23 | -------------------------------------------------------------------------------- /dev_environment/setup_dev_env_linux_vm.md: -------------------------------------------------------------------------------- 1 | # Set up L3AF Development Environment for Linux VMs 2 | There are different ways to create a Linux (i.e., Ubuntu 20.04) VM. On a local computer host, various VM software, e.g., VirtualBox, Parallels, Multipass, Windows WSL, etc. can create a Linux VM. A Linux VM can also be created in a cloud environment, e.g., Azure VM. The following procedures illustrate how to set up a L3AF development environment for those VMs if Vagrant doesn't support them. 3 | 4 | # Host Prerequisites 5 | * [L3AFD source code](https://github.com/l3af-project/l3afd) 6 | * [curl](https://curl.se/) 7 | * [hey](https://github.com/rakyll/hey) or any HTTP load generator 8 | * A web browser 9 | * A Linux VM running on the host or in a cloud (record the login information while creating the Linux VM, and root access is required.) 10 | 11 | # Trying out L3AF 12 | 1. Log into the Linux virtual machine, and run "sudo -i" to change to the root user. 13 | 2. Run the script `setup_linux_dev_env.sh` 14 | 3. Pass `--docker` argument to `setup_linux_dev_env.sh` for running L3AFd as a docker container 15 | 16 | Now go back to the [README.md](README.md) for the host to configure L3AFD to execute sample eBPF programs. 17 | -------------------------------------------------------------------------------- /dev_environment/cfg/prometheus.yml: -------------------------------------------------------------------------------- 1 | # Sample config for Prometheus. 2 | 3 | global: 4 | scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. 5 | evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. 6 | # scrape_timeout is set to the global default (10s). 7 | 8 | # Attach these labels to any time series or alerts when communicating with 9 | # external systems (federation, remote storage, Alertmanager). 10 | external_labels: 11 | monitor: 'example' 12 | 13 | # Alertmanager configuration 14 | alerting: 15 | alertmanagers: 16 | - static_configs: 17 | - targets: ['localhost:9093'] 18 | 19 | # Load rules once and periodically evaluate them according to the global 'evaluation_interval'. 20 | rule_files: 21 | # - "first_rules.yml" 22 | # - "second_rules.yml" 23 | 24 | # A scrape configuration containing exactly one endpoint to scrape: 25 | # Here it's Prometheus itself. 26 | scrape_configs: 27 | # The job name is added as a label `job=` to any timeseries scraped from this config. 28 | - job_name: 'prometheus' 29 | 30 | # Override the global default and scrape targets from this job every 5 seconds. 31 | scrape_interval: 5s 32 | scrape_timeout: 5s 33 | 34 | # metrics_path defaults to '/metrics' 35 | # scheme defaults to 'http'. 36 | 37 | static_configs: 38 | - targets: ['localhost:9090'] 39 | 40 | - job_name: node 41 | # If prometheus-node-exporter is installed, grab stats about the local 42 | # machine by default. 43 | static_configs: 44 | - targets: ['localhost:9100'] 45 | 46 | - job_name: l3af 47 | # If prometheus-node-exporter is installed, grab stats about the local 48 | # machine by default. 49 | static_configs: 50 | - targets: ['localhost:8898'] 51 | -------------------------------------------------------------------------------- /dev_environment/cfg/l3afd.cfg: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | 3 | [l3afd] 4 | pid-file: /var/run/l3afd.pid 5 | datacenter: dummy 6 | bpf-dir: /dev/shm 7 | bpf-log-dir: 8 | kernel-major-version: 5 9 | kernel-minor-version: 15 10 | shutdown-timeout: 25s 11 | http-client-timeout: 10s 12 | max-ebpf-restart-count: 3 13 | bpf-chaining-enabled: true 14 | swagger-api-enabled: true 15 | environment: DEV 16 | BpfMapDefaultPath: /sys/fs/bpf 17 | 18 | [ebpf-repo] 19 | url: file:///srv/l3afd 20 | 21 | [web] 22 | metrics-addr: 0.0.0.0:8898 23 | ebpf-poll-interval: 30s 24 | n-metric-samples: 20 25 | 26 | [xdp-root] 27 | package-name: xdp-root 28 | artifact: l3af_xdp_root.tar.gz 29 | command: xdp_root 30 | ingress-map-name: xdp_root_array 31 | version: latest 32 | object-file: xdp_root.bpf.o 33 | entry-function-name: xdp_root 34 | 35 | [tc-root] 36 | package-name: tc-root 37 | artifact: l3af_tc_root.tar.gz 38 | ingress-map-name: tc_ingress_root_array 39 | egress-map-name: tc_egress_root_array 40 | command: tc_root 41 | version: latest 42 | ingress-object-file: tc_root_ingress.bpf.o 43 | egress-object-file: tc_root_egress.bpf.o 44 | ingress-entry-function-name: tc_ingress_root 45 | egress-entry-function-name: tc_egress_root 46 | 47 | [ebpf-chain-debug] 48 | addr: 0.0.0.0:8899 49 | enabled: true 50 | 51 | [l3af-configs] 52 | restapi-addr: 0.0.0.0:7080 53 | 54 | [l3af-config-store] 55 | filename: /var/l3afd/l3af-config.json 56 | 57 | [mtls] 58 | enabled: false 59 | # TLS_1_2 or TLS_1_3 60 | # min-tls-version: TLS_1_3 61 | # cert-dir: /etc/l3af/certs 62 | # cacert-filename: ca.pem 63 | # server-crt-filename: server.crt 64 | # server-key-filename: server.key 65 | # how many days before expiry you want warning 66 | # cert-expiry-warning-days: 30 67 | # multiple domains seperated by comma 68 | # literal and regex are validated in lowercase 69 | # san-match-rules: .+l3afd.l3af.io,.*l3af.l3af.io,^l3afd.l3af.io$ 70 | 71 | [l3af-config-store] 72 | filename: /var/l3afd/l3af-config.json 73 | 74 | [graceful-restart] 75 | restart-artifacts-url: file:///srv/l3afd 76 | time-to-restart: 7 77 | basepath: /usr/local/l3afd 78 | version-limit: 100 79 | -------------------------------------------------------------------------------- /dev_environment/provision.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | # Copy grafana configs and dashboards into place 6 | mkdir -p /var/lib/grafana/dashboards 7 | chown grafana:grafana /var/lib/grafana/dashboards 8 | cp /vagrant/cfg/grafana/dashboards/*.json /var/lib/grafana/dashboards 9 | chown grafana:grafana /var/lib/grafana/dashboards/*.json 10 | cp /vagrant/cfg/grafana/provisioning/dashboards/l3af.yaml /etc/grafana/provisioning/dashboards 11 | chown root:grafana /etc/grafana/provisioning/dashboards/*.yaml 12 | cp /vagrant/cfg/grafana/provisioning/datasources/l3af.yaml /etc/grafana/provisioning/datasources 13 | chown root:grafana /etc/grafana/provisioning/datasources/*.yaml 14 | 15 | # Copy prometheus config and restart prometheus 16 | cp /vagrant/cfg/prometheus.yml /etc/prometheus/prometheus.yml 17 | systemctl daemon-reload 18 | systemctl restart prometheus prometheus-node-exporter 19 | 20 | # Start and enable Grafana 21 | systemctl daemon-reload 22 | systemctl start grafana-server 23 | systemctl enable grafana-server.service 24 | 25 | 26 | mkdir -p /var/log/l3af 27 | mkdir -p /var/l3afd 28 | 29 | BUILD_DIR=/root 30 | 31 | # Where to store the tar.gz build artifacts 32 | BUILD_ARTIFACT_DIR=/srv/l3afd 33 | mkdir -p $BUILD_ARTIFACT_DIR 34 | 35 | cd $BUILD_DIR 36 | 37 | # Get the eBPF-Package-Repository repo containing the eBPF programs 38 | if [ -d "eBPF-Package-Repository" ] 39 | then 40 | echo "Directory eBPF-Package-Repository exists." 41 | else 42 | git clone https://github.com/l3af-project/eBPF-Package-Repository.git 43 | fi 44 | cd eBPF-Package-Repository 45 | 46 | if [ "$(which bpftool)" == "" ]; 47 | then 48 | git clone --branch v7.2.0 --recurse-submodules https://github.com/libbpf/bpftool.git 49 | cd bpftool/src 50 | yes | make 51 | cp bpftool /usr/local/bin/ 52 | cd ../../ 53 | rm -rf bpftool 54 | fi 55 | 56 | 57 | # declare an array variable 58 | declare -a progs=("xdp-root" "ratelimiting" "connection-limit" "tc-root" "ipfix-flow-exporter" "traffic-mirroring") 59 | 60 | # Distribution code name 61 | distro=`cat /etc/os-release | grep UBUNTU_CODENAME | awk -F= '{print $2}'` 62 | 63 | # now loop through the above array and build the L3AF eBPF programs 64 | for prog in "${progs[@]}" 65 | do 66 | cd $prog 67 | make 68 | PROG_ARTIFACT_DIR=$BUILD_ARTIFACT_DIR/$prog/latest/$distro 69 | mkdir -p $PROG_ARTIFACT_DIR 70 | mv *.tar.gz $PROG_ARTIFACT_DIR 71 | cd ../ 72 | done 73 | -------------------------------------------------------------------------------- /images/logos/Color/L3AF_logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/logos/Black/L3AF_logo_Black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/logos/White/L3AF_logo_White.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/add_without_chaining_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name" : "l3af-test-host", 4 | "iface" : "ibpfbr", 5 | "ipv4_address": "192.168.15.80", 6 | "bpf_programs" : { 7 | "xdp_ingress" : [ 8 | { 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "version": "latest", 14 | "admin_status": "enabled", 15 | "prog_type": "xdp", 16 | "cfg_version": 1, 17 | "map_args": [ 18 | {"name": "rl_ports_map", "args": [{"key": 8080, "value": 1}, {"key": 8081, "value": 1}]}, 19 | {"name": "rl_config_map", "args": [{"key": 0, "value": 2}]} 20 | ], 21 | "monitor_maps": [ 22 | { "name": "rl_drop_count_map", "key": 0, "aggregator": "scalar"}, 23 | { "name": "rl_recv_count_map", "key": 0, "aggregator": "max-rate"} 24 | ], 25 | "object_file": "ratelimiting.bpf.o", 26 | "entry_function_name": "_xdp_ratelimiting" 27 | } 28 | ], 29 | "tc_egress": [ 30 | { 31 | "name": "ipfix-flow-exporter", 32 | "seq_id": 1, 33 | "artifact": "l3af_bpf_ipfix.tar.gz", 34 | "map_name": "ipfix_egress_jmp_table", 35 | "cmd_start": "bpf_ipfix_egress", 36 | "version": "latest", 37 | "user_program_daemon": true, 38 | "admin_status": "enabled", 39 | "prog_type": "tc", 40 | "cfg_version": 1, 41 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 42 | "monitor_maps": null, 43 | "object_file": "bpf_ipfix_egress.bpf.o", 44 | "entry_function_name": "_egress_flow_monitoring" 45 | } 46 | ], 47 | "tc_ingress": [ 48 | { 49 | "name": "ipfix-flow-exporter", 50 | "seq_id": 1, 51 | "artifact": "l3af_bpf_ipfix.tar.gz", 52 | "map_name": "ipfix_ingress_jmp_table", 53 | "cmd_start": "bpf_ipfix_ingress", 54 | "version": "latest", 55 | "user_program_daemon": true, 56 | "admin_status": "enabled", 57 | "prog_type": "tc", 58 | "cfg_version": 1, 59 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 60 | "monitor_maps": null, 61 | "object_file": "bpf_ipfix_ingress.bpf.o", 62 | "entry_function_name": "_ingress_flow_monitoring" 63 | } 64 | ] 65 | } 66 | } 67 | ] 68 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/upd_without_chaining_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name" : "l3af-test-host", 4 | "iface" : "ibpfbr", 5 | "ipv4_address": "192.168.15.80", 6 | "bpf_programs" : { 7 | "xdp_ingress" : [ 8 | { 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "version": "latest", 14 | "admin_status": "enabled", 15 | "prog_type": "xdp", 16 | "cfg_version": 1, 17 | "map_args": [ 18 | {"name": "rl_ports_map", "args": [{"key": 8080, "value": 1}, {"key": 8081, "value": 1}]}, 19 | {"name": "rl_config_map", "args": [{"key": 0, "value": 5}]} 20 | ], 21 | "monitor_maps": [ 22 | { "name": "rl_drop_count_map", "key": 0, "aggregator": "scalar"}, 23 | { "name": "rl_recv_count_map", "key": 0, "aggregator": "max-rate"} 24 | ], 25 | "object_file": "ratelimiting.bpf.o", 26 | "entry_function_name": "_xdp_ratelimiting" 27 | } 28 | ], 29 | "tc_egress": [ 30 | { 31 | "name": "ipfix-flow-exporter", 32 | "seq_id": 1, 33 | "artifact": "l3af_bpf_ipfix.tar.gz", 34 | "map_name": "ipfix_egress_jmp_table", 35 | "cmd_start": "bpf_ipfix_egress", 36 | "version": "latest", 37 | "user_program_daemon": true, 38 | "admin_status": "enabled", 39 | "prog_type": "tc", 40 | "cfg_version": 1, 41 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 42 | "monitor_maps": null, 43 | "object_file": "bpf_ipfix_egress.bpf.o", 44 | "entry_function_name": "_egress_flow_monitoring" 45 | } 46 | ], 47 | "tc_ingress": [ 48 | { 49 | "name": "ipfix-flow-exporter", 50 | "seq_id": 1, 51 | "artifact": "l3af_bpf_ipfix.tar.gz", 52 | "map_name": "ipfix_ingress_jmp_table", 53 | "cmd_start": "bpf_ipfix_ingress", 54 | "version": "latest", 55 | "user_program_daemon": true, 56 | "admin_status": "enabled", 57 | "prog_type": "tc", 58 | "cfg_version": 1, 59 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 60 | "monitor_maps": null, 61 | "object_file": "bpf_ipfix_ingress.bpf.o", 62 | "entry_function_name": "_ingress_flow_monitoring" 63 | } 64 | ] 65 | } 66 | } 67 | ] 68 | -------------------------------------------------------------------------------- /dev_environment/cfg/traffic_mirroring_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name": "l3af-local-test", 4 | "iface": "enp0s3", 5 | "bpf_programs": { 6 | "tc_ingress": [ 7 | { 8 | "name": "traffic-mirroring", 9 | "seq_id": 2, 10 | "artifact": "l3af_traffic_mirroring.tar.gz", 11 | "cmd_start": "mirroring", 12 | "version": "latest", 13 | "map_name": "mirroring_ingress_jmp_table", 14 | "admin_status": "enabled", 15 | "prog_type": "tc", 16 | "cfg_version": 1, 17 | "start_args": { 18 | "src-address": "0.0.0.0", 19 | "tunnel-interface-name": "gue1", 20 | "tunnel-local-port": "6080", 21 | "tunnel-remote-port": "6080", 22 | "tunnel-remote-address": "192.168.10.50", 23 | "redirect-to": "enp0s8", 24 | "src-port": "0", 25 | "dst-port": "8080", 26 | "protocol": "tcp,icmp" 27 | }, 28 | "monitor_maps": [], 29 | "object_file": "mirroring_ingress.bpf.o", 30 | "entry_function_name": "_ingress_redirect" 31 | 32 | } 33 | ], 34 | "tc_egress": [ 35 | { 36 | "name": "traffic-mirroring", 37 | "seq_id": 2, 38 | "artifact": "l3af_traffic_mirroring.tar.gz", 39 | "cmd_start": "mirroring", 40 | "version": "latest", 41 | "map_name": "mirroring_egress_jmp_table", 42 | "admin_status": "enabled", 43 | "prog_type": "tc", 44 | "cfg_version": 1, 45 | "start_args": { 46 | "dst-address": "0.0.0.0", 47 | "tunnel-interface-name": "gue1", 48 | "tunnel-local-port": "6080", 49 | "tunnel-remote-port": "6080", 50 | "tunnel-remote-address": "192.168.10.50", 51 | "redirect-to": "enp0s8", 52 | "src-port": "8080", 53 | "dst-port": "0", 54 | "protocol": "tcp,icmp" 55 | }, 56 | "monitor_maps": [], 57 | "object_file": "mirroring_egress.bpf.o", 58 | "entry_function_name": "_egress_redirect" 59 | } 60 | ] 61 | } 62 | } 63 | ] 64 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/add_tm_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name": "l3af-test-host", 4 | "iface": "ibpfbr", 5 | "ipv4_address": "192.168.15.80", 6 | "bpf_programs": { 7 | "tc_ingress": [ 8 | { 9 | "name": "traffic-mirroring", 10 | "seq_id": 2, 11 | "artifact": "l3af_traffic_mirroring.tar.gz", 12 | "cmd_start": "mirroring", 13 | "version": "latest", 14 | "map_name": "mirroring_ingress_jmp_table", 15 | "admin_status": "enabled", 16 | "prog_type": "tc", 17 | "cfg_version": 1, 18 | "start_args": { 19 | "src-address": "0.0.0.0", 20 | "tunnel-interface-name": "gue1", 21 | "tunnel-local-port": "6080", 22 | "tunnel-remote-port": "6081", 23 | "tunnel-remote-address": "127.0.0.1", 24 | "redirect-to": "lo", 25 | "src-port": "0", 26 | "dst-port": "8080", 27 | "protocol": "tcp,icmp" 28 | }, 29 | "monitor_maps": [], 30 | "object_file": "mirroring_ingress.bpf.o", 31 | "entry_function_name": "_ingress_redirect" 32 | } 33 | ], 34 | "tc_egress": [ 35 | { 36 | "name": "traffic-mirroring", 37 | "seq_id": 2, 38 | "artifact": "l3af_traffic_mirroring.tar.gz", 39 | "cmd_start": "mirroring", 40 | "version": "latest", 41 | "map_name": "mirroring_egress_jmp_table", 42 | "admin_status": "enabled", 43 | "prog_type": "tc", 44 | "cfg_version": 1, 45 | "start_args": { 46 | "dst-address": "0.0.0.0", 47 | "tunnel-interface-name": "gue1", 48 | "tunnel-local-port": "6080", 49 | "tunnel-remote-port": "6081", 50 | "tunnel-remote-address": "127.0.0.1", 51 | "redirect-to": "lo", 52 | "src-port": "0", 53 | "dst-port": "0", 54 | "protocol": "tcp,icmp" 55 | }, 56 | "monitor_maps": [], 57 | "object_file": "mirroring_egress.bpf.o", 58 | "entry_function_name": "_egress_redirect" 59 | } 60 | ] 61 | } 62 | } 63 | ] 64 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/exp_output_7.json: -------------------------------------------------------------------------------- 1 | { 2 | "host_name": "l3af-test-host", 3 | "iface": "ibpfbr", 4 | "ipv4_address": "192.168.15.80", 5 | "bpf_programs": { 6 | "xdp_ingress": null, 7 | "tc_ingress": [ 8 | { 9 | "id": 0, 10 | "name": "traffic-mirroring", 11 | "seq_id": 2, 12 | "artifact": "l3af_traffic_mirroring.tar.gz", 13 | "map_name": "mirroring_ingress_jmp_table", 14 | "cmd_start": "mirroring", 15 | "cmd_stop": "", 16 | "cmd_status": "", 17 | "cmd_config": "", 18 | "cmd_update": "", 19 | "version": "latest", 20 | "user_program_daemon": false, 21 | "is_plugin": false, 22 | "cpu": 0, 23 | "memory": 0, 24 | "admin_status": "enabled", 25 | "prog_type": "tc", 26 | "rules_file": "", 27 | "rules": "", 28 | "config_file_path": "", 29 | "cfg_version": 1, 30 | "start_args": { 31 | "dst-port": "8080", 32 | "protocol": "tcp,icmp", 33 | "redirect-to": "lo", 34 | "src-address": "0.0.0.0", 35 | "src-port": "0", 36 | "tunnel-interface-name": "gue1", 37 | "tunnel-local-port": "6080", 38 | "tunnel-remote-address": "127.0.0.1", 39 | "tunnel-remote-port": "6081" 40 | }, 41 | "stop_args": null, 42 | "status_args": null, 43 | "update_args": null, 44 | "map_args": null, 45 | "config_args": null, 46 | "monitor_maps": [], 47 | "ebpf_package_repo_url": "", 48 | "object_file": "mirroring_ingress.bpf.o", 49 | "entry_function_name": "_ingress_redirect" 50 | } 51 | ], 52 | "tc_egress": [ 53 | { 54 | "id": 0, 55 | "name": "traffic-mirroring", 56 | "seq_id": 2, 57 | "artifact": "l3af_traffic_mirroring.tar.gz", 58 | "map_name": "mirroring_egress_jmp_table", 59 | "cmd_start": "mirroring", 60 | "cmd_stop": "", 61 | "cmd_status": "", 62 | "cmd_config": "", 63 | "cmd_update": "", 64 | "version": "latest", 65 | "user_program_daemon": false, 66 | "is_plugin": false, 67 | "cpu": 0, 68 | "memory": 0, 69 | "admin_status": "enabled", 70 | "prog_type": "tc", 71 | "rules_file": "", 72 | "rules": "", 73 | "config_file_path": "", 74 | "cfg_version": 1, 75 | "start_args": { 76 | "dst-address": "0.0.0.0", 77 | "dst-port": "0", 78 | "protocol": "tcp,icmp", 79 | "redirect-to": "lo", 80 | "src-port": "0", 81 | "tunnel-interface-name": "gue1", 82 | "tunnel-local-port": "6080", 83 | "tunnel-remote-address": "127.0.0.1", 84 | "tunnel-remote-port": "6081" 85 | }, 86 | "stop_args": null, 87 | "status_args": null, 88 | "update_args": null, 89 | "map_args": null, 90 | "config_args": null, 91 | "monitor_maps": [], 92 | "ebpf_package_repo_url": "", 93 | "object_file": "mirroring_egress.bpf.o", 94 | "entry_function_name": "_egress_redirect" 95 | } 96 | ], 97 | "probes": null 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /dev_environment/cfg/payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name": "l3af-local-test", 4 | "iface": "enp0s3", 5 | "ipv4_address": "192.168.105.2", 6 | "bpf_programs" : { 7 | "xdp_ingress" : [ 8 | { 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "version": "latest", 14 | "admin_status": "enabled", 15 | "prog_type": "xdp", 16 | "cfg_version": 1, 17 | "map_args": [ 18 | {"name": "rl_ports_map", "args": [{"key": 8080, "value": 1}, {"key": 8081, "value": 1}]}, 19 | {"name": "rl_config_map", "args": [{"key": 0, "value": 2}]} 20 | ], 21 | "monitor_maps": [ 22 | { "name": "rl_drop_count_map", "key": 0, "aggregator": "scalar"}, 23 | { "name": "rl_recv_count_map", "key": 0, "aggregator": "max-rate"} 24 | ], 25 | "object_file": "ratelimiting.bpf.o", 26 | "entry_function_name": "_xdp_ratelimiting" 27 | }, 28 | { 29 | "name": "connection-limit", 30 | "seq_id": 2, 31 | "artifact": "l3af_connection_limit.tar.gz", 32 | "map_name": "xdp_cl_ingress_next_prog", 33 | "cmd_start": "connection_limit", 34 | "version": "latest", 35 | "admin_status": "enabled", 36 | "prog_type": "xdp", 37 | "cfg_version": 1, 38 | "map_args": [ 39 | {"name": "cl_tcp_conns", "args": [{"key": 8080, "value": 1}, {"key": 8081, "value": 1}]}, 40 | {"name": "cl_max_conn", "args": [{"key": 0, "value": 2}]} 41 | ], 42 | "monitor_maps": [ 43 | { "name": "cl_recv_count_map", "key": 0, "aggregator": "scalar"}, 44 | { "name": "cl_drop_count_map", "key": 0, "aggregator": "scalar" }, 45 | { "name": "cl_conn_count", "key": 0, "aggregator": "scalar" } 46 | ], 47 | "object_file": "connection_limit.bpf.o", 48 | "entry_function_name": "_xdp_limit_conn" 49 | } 50 | ], 51 | "tc_egress": [ 52 | { 53 | "name": "ipfix-flow-exporter", 54 | "seq_id": 1, 55 | "artifact": "l3af_bpf_ipfix.tar.gz", 56 | "map_name": "ipfix_egress_jmp_table", 57 | "cmd_start": "bpf_ipfix_egress", 58 | "version": "latest", 59 | "user_program_daemon": true, 60 | "admin_status": "enabled", 61 | "prog_type": "tc", 62 | "cfg_version": 1, 63 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 64 | "monitor_maps": null, 65 | "object_file": "bpf_ipfix_egress.bpf.o", 66 | "entry_function_name": "_egress_flow_monitoring" 67 | } 68 | ], 69 | "tc_ingress": [ 70 | { 71 | "name": "ipfix-flow-exporter", 72 | "seq_id": 1, 73 | "artifact": "l3af_bpf_ipfix.tar.gz", 74 | "map_name": "ipfix_ingress_jmp_table", 75 | "cmd_start": "bpf_ipfix_ingress", 76 | "version": "latest", 77 | "user_program_daemon": true, 78 | "admin_status": "enabled", 79 | "prog_type": "tc", 80 | "cfg_version": 1, 81 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 82 | "monitor_maps": null, 83 | "object_file": "bpf_ipfix_ingress.bpf.o", 84 | "entry_function_name": "_ingress_flow_monitoring" 85 | } 86 | ] 87 | } 88 | } 89 | ] 90 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/add_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name" : "l3af-test-host", 4 | "iface" : "ibpfbr", 5 | "ipv4_address": "192.168.15.80", 6 | "bpf_programs" : { 7 | "xdp_ingress" : [ 8 | { 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "version": "latest", 14 | "admin_status": "enabled", 15 | "prog_type": "xdp", 16 | "cfg_version": 1, 17 | "map_args": [ 18 | {"name": "rl_ports_map", "args": [{"key": 8080, "value": 1}, {"key": 8081, "value": 1}]}, 19 | {"name": "rl_config_map", "args": [{"key": 0, "value": 2}]} 20 | ], 21 | "monitor_maps": [ 22 | { "name": "rl_drop_count_map", "key": 0, "aggregator": "scalar"}, 23 | { "name": "rl_recv_count_map", "key": 0, "aggregator": "max-rate"} 24 | ], 25 | "object_file": "ratelimiting.bpf.o", 26 | "entry_function_name": "_xdp_ratelimiting" 27 | }, 28 | { 29 | "name": "connection-limit", 30 | "seq_id": 2, 31 | "artifact": "l3af_connection_limit.tar.gz", 32 | "map_name": "xdp_cl_ingress_next_prog", 33 | "cmd_start": "connection_limit", 34 | "version": "latest", 35 | "admin_status": "enabled", 36 | "prog_type": "xdp", 37 | "cfg_version": 1, 38 | "map_args": [ 39 | {"name": "cl_tcp_conns", "args": [{"key": 8080, "value": 1}, {"key": 8081, "value": 1}]}, 40 | {"name": "cl_max_conn", "args": [{"key": 0, "value": 2}]} 41 | ], 42 | "monitor_maps": [ 43 | { "name": "cl_recv_count_map", "key": 0, "aggregator": "scalar"}, 44 | { "name": "cl_drop_count_map", "key": 0, "aggregator": "scalar" }, 45 | { "name": "cl_conn_count", "key": 0, "aggregator": "scalar" } 46 | ], 47 | "object_file": "connection_limit.bpf.o", 48 | "entry_function_name": "_xdp_limit_conn" 49 | } 50 | ], 51 | "tc_egress": [ 52 | { 53 | "name": "ipfix-flow-exporter", 54 | "seq_id": 1, 55 | "artifact": "l3af_bpf_ipfix.tar.gz", 56 | "map_name": "ipfix_egress_jmp_table", 57 | "cmd_start": "bpf_ipfix_egress", 58 | "version": "latest", 59 | "user_program_daemon": true, 60 | "admin_status": "enabled", 61 | "prog_type": "tc", 62 | "cfg_version": 1, 63 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 64 | "monitor_maps": null, 65 | "object_file": "bpf_ipfix_egress.bpf.o", 66 | "entry_function_name": "_egress_flow_monitoring" 67 | } 68 | ], 69 | "tc_ingress": [ 70 | { 71 | "name": "ipfix-flow-exporter", 72 | "seq_id": 1, 73 | "artifact": "l3af_bpf_ipfix.tar.gz", 74 | "map_name": "ipfix_ingress_jmp_table", 75 | "cmd_start": "bpf_ipfix_ingress", 76 | "version": "latest", 77 | "user_program_daemon": true, 78 | "admin_status": "enabled", 79 | "prog_type": "tc", 80 | "cfg_version": 1, 81 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 82 | "monitor_maps": null, 83 | "object_file": "bpf_ipfix_ingress.bpf.o", 84 | "entry_function_name": "_ingress_flow_monitoring" 85 | } 86 | ] 87 | } 88 | } 89 | ] 90 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/upd_payload.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "host_name" : "l3af-test-host", 4 | "iface" : "ibpfbr", 5 | "ipv4_address": "192.168.15.80", 6 | "bpf_programs" : { 7 | "xdp_ingress" : [ 8 | { 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "version": "latest", 14 | "admin_status": "enabled", 15 | "prog_type": "xdp", 16 | "cfg_version": 1, 17 | "map_args": [ 18 | {"name": "rl_ports_map", "args": [{"key": 8080, "value": 1}, {"key": 8081, "value": 1}]}, 19 | {"name": "rl_config_map", "args": [{"key": 0, "value": 2}]} 20 | ], 21 | "monitor_maps": [ 22 | { "name": "rl_drop_count_map", "key": 0, "aggregator": "scalar"}, 23 | { "name": "rl_recv_count_map", "key": 0, "aggregator": "max-rate"} 24 | ], 25 | "object_file": "ratelimiting.bpf.o", 26 | "entry_function_name": "_xdp_ratelimiting" 27 | }, 28 | { 29 | "name": "connection-limit", 30 | "seq_id": 2, 31 | "artifact": "l3af_connection_limit.tar.gz", 32 | "map_name": "xdp_cl_ingress_next_prog", 33 | "cmd_start": "connection_limit", 34 | "version": "latest", 35 | "admin_status": "enabled", 36 | "prog_type": "xdp", 37 | "cfg_version": 1, 38 | "map_args": [ 39 | {"name": "cl_tcp_conns", "args": [{"key": 8080, "value": 1}, {"key": 8081, "value": 1}]}, 40 | {"name": "cl_max_conn", "args": [{"key": 0, "value": 5}]} 41 | ], 42 | "monitor_maps": [ 43 | { "name": "cl_recv_count_map", "key": 0, "aggregator": "scalar"}, 44 | { "name": "cl_drop_count_map", "key": 0, "aggregator": "scalar" }, 45 | { "name": "cl_conn_count", "key": 0, "aggregator": "scalar" } 46 | ], 47 | "object_file": "connection_limit.bpf.o", 48 | "entry_function_name": "_xdp_limit_conn" 49 | } 50 | ], 51 | "tc_egress": [ 52 | { 53 | "name": "ipfix-flow-exporter", 54 | "seq_id": 1, 55 | "artifact": "l3af_bpf_ipfix.tar.gz", 56 | "map_name": "ipfix_egress_jmp_table", 57 | "cmd_start": "bpf_ipfix_egress", 58 | "version": "latest", 59 | "user_program_daemon": true, 60 | "admin_status": "enabled", 61 | "prog_type": "tc", 62 | "cfg_version": 1, 63 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 64 | "monitor_maps": null, 65 | "object_file": "bpf_ipfix_egress.bpf.o", 66 | "entry_function_name": "_egress_flow_monitoring" 67 | } 68 | ], 69 | "tc_ingress": [ 70 | { 71 | "name": "ipfix-flow-exporter", 72 | "seq_id": 1, 73 | "artifact": "l3af_bpf_ipfix.tar.gz", 74 | "map_name": "ipfix_ingress_jmp_table", 75 | "cmd_start": "bpf_ipfix_ingress", 76 | "version": "latest", 77 | "user_program_daemon": true, 78 | "admin_status": "enabled", 79 | "prog_type": "tc", 80 | "cfg_version": 1, 81 | "start_args": { "collector_ip": "127.0.0.1", "collector_port": "49280", "verbose":"2" }, 82 | "monitor_maps": null, 83 | "object_file": "bpf_ipfix_ingress.bpf.o", 84 | "entry_function_name": "_ingress_flow_monitoring" 85 | } 86 | ] 87 | } 88 | } 89 | ] 90 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/exp_output_5.json: -------------------------------------------------------------------------------- 1 | { 2 | "host_name": "l3af-test-host", 3 | "iface": "ibpfbr", 4 | "ipv4_address": "192.168.15.80", 5 | "bpf_programs": { 6 | "xdp_ingress": [ 7 | { 8 | "id": 0, 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "cmd_start": "", 14 | "cmd_stop": "", 15 | "cmd_status": "", 16 | "cmd_config": "", 17 | "cmd_update": "", 18 | "version": "latest", 19 | "user_program_daemon": false, 20 | "is_plugin": false, 21 | "cpu": 0, 22 | "memory": 0, 23 | "admin_status": "enabled", 24 | "prog_type": "xdp", 25 | "rules_file": "", 26 | "rules": "", 27 | "config_file_path": "", 28 | "cfg_version": 1, 29 | "start_args": null, 30 | "stop_args": null, 31 | "status_args": null, 32 | "update_args": null, 33 | "map_args": [ 34 | { 35 | "name": "rl_ports_map", 36 | "args": [ 37 | { 38 | "key": 8080, 39 | "value": 1 40 | }, 41 | { 42 | "key": 8081, 43 | "value": 1 44 | } 45 | ] 46 | }, 47 | { 48 | "name": "rl_config_map", 49 | "args": [ 50 | { 51 | "key": 0, 52 | "value": 2 53 | } 54 | ] 55 | } 56 | ], 57 | "config_args": null, 58 | "monitor_maps": [ 59 | { 60 | "name": "rl_drop_count_map", 61 | "key": 0, 62 | "aggregator": "scalar" 63 | }, 64 | { 65 | "name": "rl_recv_count_map", 66 | "key": 0, 67 | "aggregator": "max-rate" 68 | } 69 | ], 70 | "ebpf_package_repo_url": "", 71 | "object_file": "ratelimiting.bpf.o", 72 | "entry_function_name": "_xdp_ratelimiting" 73 | } 74 | ], 75 | "tc_ingress": [ 76 | { 77 | "id": 0, 78 | "name": "ipfix-flow-exporter", 79 | "seq_id": 1, 80 | "artifact": "l3af_bpf_ipfix.tar.gz", 81 | "map_name": "ipfix_ingress_jmp_table", 82 | "cmd_start": "bpf_ipfix_ingress", 83 | "cmd_stop": "", 84 | "cmd_status": "", 85 | "cmd_config": "", 86 | "cmd_update": "", 87 | "version": "latest", 88 | "user_program_daemon": true, 89 | "is_plugin": false, 90 | "cpu": 0, 91 | "memory": 0, 92 | "admin_status": "enabled", 93 | "prog_type": "tc", 94 | "rules_file": "", 95 | "rules": "", 96 | "config_file_path": "", 97 | "cfg_version": 1, 98 | "start_args": { 99 | "collector_ip": "127.0.0.1", 100 | "collector_port": "49280", 101 | "verbose": "2" 102 | }, 103 | "stop_args": null, 104 | "status_args": null, 105 | "update_args": null, 106 | "map_args": null, 107 | "config_args": null, 108 | "monitor_maps": null, 109 | "ebpf_package_repo_url": "", 110 | "object_file": "bpf_ipfix_ingress.bpf.o", 111 | "entry_function_name": "_ingress_flow_monitoring" 112 | } 113 | ], 114 | "tc_egress": [ 115 | { 116 | "id": 0, 117 | "name": "ipfix-flow-exporter", 118 | "seq_id": 1, 119 | "artifact": "l3af_bpf_ipfix.tar.gz", 120 | "map_name": "ipfix_egress_jmp_table", 121 | "cmd_start": "bpf_ipfix_egress", 122 | "cmd_stop": "", 123 | "cmd_status": "", 124 | "cmd_config": "", 125 | "cmd_update": "", 126 | "version": "latest", 127 | "user_program_daemon": true, 128 | "is_plugin": false, 129 | "cpu": 0, 130 | "memory": 0, 131 | "admin_status": "enabled", 132 | "prog_type": "tc", 133 | "rules_file": "", 134 | "rules": "", 135 | "config_file_path": "", 136 | "cfg_version": 1, 137 | "start_args": { 138 | "collector_ip": "127.0.0.1", 139 | "collector_port": "49280", 140 | "verbose": "2" 141 | }, 142 | "stop_args": null, 143 | "status_args": null, 144 | "update_args": null, 145 | "map_args": null, 146 | "config_args": null, 147 | "monitor_maps": null, 148 | "ebpf_package_repo_url": "", 149 | "object_file": "bpf_ipfix_egress.bpf.o", 150 | "entry_function_name": "_egress_flow_monitoring" 151 | } 152 | ], 153 | "probes": null 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/exp_output_6.json: -------------------------------------------------------------------------------- 1 | { 2 | "host_name": "l3af-test-host", 3 | "iface": "ibpfbr", 4 | "ipv4_address": "192.168.15.80", 5 | "bpf_programs": { 6 | "xdp_ingress": [ 7 | { 8 | "id": 0, 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "cmd_start": "", 14 | "cmd_stop": "", 15 | "cmd_status": "", 16 | "cmd_config": "", 17 | "cmd_update": "", 18 | "version": "latest", 19 | "user_program_daemon": false, 20 | "is_plugin": false, 21 | "cpu": 0, 22 | "memory": 0, 23 | "admin_status": "enabled", 24 | "prog_type": "xdp", 25 | "rules_file": "", 26 | "rules": "", 27 | "config_file_path": "", 28 | "cfg_version": 1, 29 | "start_args": null, 30 | "stop_args": null, 31 | "status_args": null, 32 | "update_args": null, 33 | "map_args": [ 34 | { 35 | "name": "rl_ports_map", 36 | "args": [ 37 | { 38 | "key": 8080, 39 | "value": 1 40 | }, 41 | { 42 | "key": 8081, 43 | "value": 1 44 | } 45 | ] 46 | }, 47 | { 48 | "name": "rl_config_map", 49 | "args": [ 50 | { 51 | "key": 0, 52 | "value": 5 53 | } 54 | ] 55 | } 56 | ], 57 | "config_args": null, 58 | "monitor_maps": [ 59 | { 60 | "name": "rl_drop_count_map", 61 | "key": 0, 62 | "aggregator": "scalar" 63 | }, 64 | { 65 | "name": "rl_recv_count_map", 66 | "key": 0, 67 | "aggregator": "max-rate" 68 | } 69 | ], 70 | "ebpf_package_repo_url": "", 71 | "object_file": "ratelimiting.bpf.o", 72 | "entry_function_name": "_xdp_ratelimiting" 73 | } 74 | ], 75 | "tc_ingress": [ 76 | { 77 | "id": 0, 78 | "name": "ipfix-flow-exporter", 79 | "seq_id": 1, 80 | "artifact": "l3af_bpf_ipfix.tar.gz", 81 | "map_name": "ipfix_ingress_jmp_table", 82 | "cmd_start": "bpf_ipfix_ingress", 83 | "cmd_stop": "", 84 | "cmd_status": "", 85 | "cmd_config": "", 86 | "cmd_update": "", 87 | "version": "latest", 88 | "user_program_daemon": true, 89 | "is_plugin": false, 90 | "cpu": 0, 91 | "memory": 0, 92 | "admin_status": "enabled", 93 | "prog_type": "tc", 94 | "rules_file": "", 95 | "rules": "", 96 | "config_file_path": "", 97 | "cfg_version": 1, 98 | "start_args": { 99 | "collector_ip": "127.0.0.1", 100 | "collector_port": "49280", 101 | "verbose": "2" 102 | }, 103 | "stop_args": null, 104 | "status_args": null, 105 | "update_args": null, 106 | "map_args": null, 107 | "config_args": null, 108 | "monitor_maps": null, 109 | "ebpf_package_repo_url": "", 110 | "object_file": "bpf_ipfix_ingress.bpf.o", 111 | "entry_function_name": "_ingress_flow_monitoring" 112 | } 113 | ], 114 | "tc_egress": [ 115 | { 116 | "id": 0, 117 | "name": "ipfix-flow-exporter", 118 | "seq_id": 1, 119 | "artifact": "l3af_bpf_ipfix.tar.gz", 120 | "map_name": "ipfix_egress_jmp_table", 121 | "cmd_start": "bpf_ipfix_egress", 122 | "cmd_stop": "", 123 | "cmd_status": "", 124 | "cmd_config": "", 125 | "cmd_update": "", 126 | "version": "latest", 127 | "user_program_daemon": true, 128 | "is_plugin": false, 129 | "cpu": 0, 130 | "memory": 0, 131 | "admin_status": "enabled", 132 | "prog_type": "tc", 133 | "rules_file": "", 134 | "rules": "", 135 | "config_file_path": "", 136 | "cfg_version": 1, 137 | "start_args": { 138 | "collector_ip": "127.0.0.1", 139 | "collector_port": "49280", 140 | "verbose": "2" 141 | }, 142 | "stop_args": null, 143 | "status_args": null, 144 | "update_args": null, 145 | "map_args": null, 146 | "config_args": null, 147 | "monitor_maps": null, 148 | "ebpf_package_repo_url": "", 149 | "object_file": "bpf_ipfix_egress.bpf.o", 150 | "entry_function_name": "_egress_flow_monitoring" 151 | } 152 | ], 153 | "probes": null 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /dev_environment/README.md: -------------------------------------------------------------------------------- 1 | # L3AF Development Environment 2 | 3 | The L3AF dev environment is a [Vagrant](https://www.vagrantup.com/) virtual 4 | machine environment that allows users to develop, test, or just try out L3AF. 5 | 6 | As an alternative to Vagrant, the l3af development environment can be set up on a standalone Linux virtual machine. Please see [setup_dev_env_linux_vm.md](setup_dev_env_linux_vm.md) for the instructions. Use this method for MAC/PC with Arm CPUs, Windows WSL, or cloud provider Linux VMs. 7 | 8 | # Overview 9 | 10 | The L3AF dev environment automation sets up a virtual machine that contains: 11 | 12 | * Dependencies required to build L3AFD and eBPF programs 13 | * Simple web servers (written in Go) to which test traffic can be sent 14 | * Prometheus and Grafana for metrics 15 | * A local eBPF Package Repository (simple Python file server) 16 | 17 | The host machine can access various services on the virtual machine via 18 | user-configured ports. 19 | 20 | Here is a visual overview: 21 | 22 | ![L3AF dev env overview](../images/L3AF_dev_env.png) 23 | 24 | # Host Prerequisites 25 | 26 | * [Vagrant](https://www.vagrantup.com/) 27 | * [VirtualBox](https://www.virtualbox.org/) 28 | * [L3AFD source code](https://github.com/l3af-project/l3afd) 29 | * [curl](https://curl.se/) 30 | * [hey](https://github.com/rakyll/hey) or any HTTP load generator 31 | * A web browser 32 | 33 | # Trying out L3AF 34 | 35 | * Edit [config.yaml](config.yaml) to point to the 36 | [source code](https://github.com/l3af-project/l3afd) on your host machine. 37 | This code will be mounted by the virtual machine. Additionally, you may modify 38 | the default ports used on the host to access services on the virtual machine. 39 | (Note, however, that this document will refer to the default ports.) 40 | * If you don't already have the vagant reload plugin, you'll need to install it, 41 | `vagrant plugin install vagrant-reload`. 42 | * Run `vagrant up`. This should take just a few minutes to bring up the 43 | virtual machine from scratch. 44 | * Verify that the host can send traffic to a web server running on the VM: 45 | `hey -n 200 -c 20 http://localhost:18080`. This command should return quickly 46 | and result in successful HTTP responses (200 OK). This command should also return a latency distribution histogram that shows 47 | most traffic clustered near the top of the graph at very low latency.

48 | * Run `vagrant ssh l3af`, this will log you into the virtual machine 49 | * On the VM, go to `~/code/l3afd` and run `make install` 50 | * Run `l3afd` as root: 51 | `sudo /usr/local/l3afd/latest/l3afd --config /usr/local/l3afd/latest/l3afd.cfg` 52 | * On the host, configure L3AFD to execute sample eBPF programs by running 53 | `curl -X POST http://localhost:37080/l3af/configs/v1/add -d 54 | "@cfg/payload.json"`. The [payload.json](cfg/payload.json) file can be 55 | inspected and modified as desired. For more information on the L3AFD API see 56 | the [L3AFD API documentation](https://github.com/l3af-project/l3afd/tree/main/docs/api). 57 | * The Swagger UI on the host machine `http://localhost:37080/swagger/index.html` 58 | can also be used to add or remove which eBPF programs are running inside the 59 | virtual machine. 60 | * Verify the eBPF programs from [payload.json](cfg/payload.json) are running by 61 | querying the L3AFD debug API from the host: 62 | `curl http://localhost:38899/bpfs/enp0s3`. This command assumes `enp0s3` is a 63 | valid network interface on the VM. 64 | * Once again send traffic to the VM web server: 65 | `hey -n 200 -c 20 http://localhost:18080`. The traffic will now be running 66 | through the eBPF programs (which may affect results dramatically depending 67 | on which eBPF programs are running and how they are configured). If the rate limiter eBPF program is loaded, this command should output a latency distribution histogram that 68 | is more distributed.

69 | * To see the eBPF program metrics, browse to `http://localhost:33000` on the 70 | host and log in to Grafana with the default username and password of `admin`. 71 | After logging in you will be able to view the preconfigured dashboards. Example 72 |

alt text

73 | * Additional steps for testing out traffic mirroring: 74 | 1. Set `traffic_mirroring: 'true'` in [config.yaml](config.yaml) 75 | 2. Redeploy the Vagrant script (`vagrant reload --provision`) to reflect new changes, such as creation of a GUE tunnel and an additional VM (Collector) 76 | 3. Start traffic mirrroing via `curl -X POST http://localhost:37080/l3af/configs/v1/add -d "@cfg/traffic_mirroring_payload.json"` from the host 77 | 4. Delete the default route by executing this command (`sudo ip r del 192.168.10.50 via 192.168.10.1 dev enp0s8`) on l3af-VM as it is not required in the current vagrant environment 78 | 5. SSH into Collector VM via `vagrant ssh collector` command and execute `sudo tcpdump -i enp0s8` to see the mirrored-GUE packets and `sudo tcpdump -i gue1` to see the mirrored-original packets when we send traffic to the l3af VM web server (`hey -n 200 -c 20 http://localhost:18080`) from the host 79 | * Additional steps if you would like to use a custom backend instead of Prometheus for observability through Opentelemetry Collector: 80 | 1. Set `otel_collector: 'true'` in [config.yaml](config.yaml) 81 | 2. Set `endpoint` field in [otel-collector-config.yaml](../dev_environment/cfg/otel-collector-config.yml) under `exporters` > `prometheusremotewrite`. Refer [Opentelemetry Exporters](https://opentelemetry.io/docs/collector/configuration/#exporters) documentation to know more. 82 | 3. Redeploy the Vagrant script (`vagrant reload --provision`) to install the Opentelemetry Collector binary. 83 | -------------------------------------------------------------------------------- /dev_environment/cfg/grafana/dashboards/l3af_rate_limiting.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "target": { 12 | "limit": 100, 13 | "matchAny": false, 14 | "tags": [], 15 | "type": "dashboard" 16 | }, 17 | "type": "dashboard" 18 | } 19 | ] 20 | }, 21 | "editable": true, 22 | "gnetId": null, 23 | "graphTooltip": 0, 24 | "id": 1, 25 | "links": [], 26 | "panels": [ 27 | { 28 | "aliasColors": {}, 29 | "bars": false, 30 | "dashLength": 10, 31 | "dashes": false, 32 | "datasource": null, 33 | "fieldConfig": { 34 | "defaults": { 35 | "links": [] 36 | }, 37 | "overrides": [] 38 | }, 39 | "fill": 0, 40 | "fillGradient": 0, 41 | "gridPos": { 42 | "h": 8, 43 | "w": 8, 44 | "x": 0, 45 | "y": 0 46 | }, 47 | "hiddenSeries": false, 48 | "id": 8, 49 | "legend": { 50 | "alignAsTable": true, 51 | "avg": true, 52 | "current": true, 53 | "hideEmpty": true, 54 | "hideZero": true, 55 | "max": true, 56 | "min": false, 57 | "rightSide": false, 58 | "show": true, 59 | "sort": "current", 60 | "sortDesc": true, 61 | "total": false, 62 | "values": true 63 | }, 64 | "lines": true, 65 | "linewidth": 1, 66 | "links": [], 67 | "nullPointMode": "null", 68 | "options": { 69 | "alertThreshold": true 70 | }, 71 | "percentage": false, 72 | "pluginVersion": "8.1.5", 73 | "pointradius": 5, 74 | "points": false, 75 | "renderer": "flot", 76 | "seriesOverrides": [], 77 | "spaceLength": 10, 78 | "stack": false, 79 | "steppedLine": false, 80 | "targets": [ 81 | { 82 | "exemplar": true, 83 | "expr": "l3afd_BPFMonitorMap{ebpf_program=\"ratelimiting\",map_name=\"rl_recv_count_map_0_max-rate\"}", 84 | "hide": false, 85 | "interval": "30s", 86 | "legendFormat": "{{host}}", 87 | "refId": "A" 88 | } 89 | ], 90 | "thresholds": [], 91 | "timeFrom": null, 92 | "timeRegions": [], 93 | "timeShift": null, 94 | "title": "peak recv conns per sec", 95 | "tooltip": { 96 | "shared": true, 97 | "sort": 2, 98 | "value_type": "individual" 99 | }, 100 | "type": "graph", 101 | "xaxis": { 102 | "buckets": null, 103 | "mode": "time", 104 | "name": null, 105 | "show": true, 106 | "values": [] 107 | }, 108 | "yaxes": [ 109 | { 110 | "format": "short", 111 | "label": "Recv conns / sec", 112 | "logBase": 1, 113 | "max": null, 114 | "min": "0", 115 | "show": true 116 | }, 117 | { 118 | "format": "short", 119 | "label": null, 120 | "logBase": 1, 121 | "max": null, 122 | "min": null, 123 | "show": false 124 | } 125 | ], 126 | "yaxis": { 127 | "align": false, 128 | "alignLevel": null 129 | } 130 | }, 131 | { 132 | "aliasColors": {}, 133 | "bars": false, 134 | "dashLength": 10, 135 | "dashes": false, 136 | "datasource": null, 137 | "fieldConfig": { 138 | "defaults": { 139 | "links": [] 140 | }, 141 | "overrides": [] 142 | }, 143 | "fill": 0, 144 | "fillGradient": 0, 145 | "gridPos": { 146 | "h": 7, 147 | "w": 8, 148 | "x": 0, 149 | "y": 8 150 | }, 151 | "hiddenSeries": false, 152 | "id": 7, 153 | "legend": { 154 | "alignAsTable": true, 155 | "avg": true, 156 | "current": true, 157 | "hideEmpty": true, 158 | "hideZero": true, 159 | "max": true, 160 | "min": false, 161 | "rightSide": false, 162 | "show": true, 163 | "sort": "current", 164 | "sortDesc": true, 165 | "total": false, 166 | "values": true 167 | }, 168 | "lines": true, 169 | "linewidth": 1, 170 | "links": [], 171 | "nullPointMode": "null", 172 | "options": { 173 | "alertThreshold": true 174 | }, 175 | "percentage": false, 176 | "pluginVersion": "8.1.5", 177 | "pointradius": 5, 178 | "points": false, 179 | "renderer": "flot", 180 | "seriesOverrides": [], 181 | "spaceLength": 10, 182 | "stack": false, 183 | "steppedLine": false, 184 | "targets": [ 185 | { 186 | "exemplar": true, 187 | "expr": "sum(irate(l3afd_BPFMonitorMap{map_name=\"rl_drop_count_map_0_scalar\",ebpf_program=\"ratelimiting\"}[5m])) by (host)", 188 | "interval": "", 189 | "legendFormat": "{{host}}", 190 | "refId": "A" 191 | } 192 | ], 193 | "thresholds": [], 194 | "timeFrom": null, 195 | "timeRegions": [], 196 | "timeShift": null, 197 | "title": "dropped connections", 198 | "tooltip": { 199 | "shared": true, 200 | "sort": 2, 201 | "value_type": "individual" 202 | }, 203 | "type": "graph", 204 | "xaxis": { 205 | "buckets": null, 206 | "mode": "time", 207 | "name": null, 208 | "show": true, 209 | "values": [] 210 | }, 211 | "yaxes": [ 212 | { 213 | "format": "short", 214 | "label": "Drop conn / sec", 215 | "logBase": 1, 216 | "max": null, 217 | "min": "0", 218 | "show": true 219 | }, 220 | { 221 | "format": "short", 222 | "label": null, 223 | "logBase": 1, 224 | "max": null, 225 | "min": null, 226 | "show": false 227 | } 228 | ], 229 | "yaxis": { 230 | "align": false, 231 | "alignLevel": null 232 | } 233 | } 234 | ], 235 | "refresh": "30s", 236 | "schemaVersion": 30, 237 | "style": "dark", 238 | "tags": [], 239 | "templating": { 240 | "list": [] 241 | }, 242 | "time": { 243 | "from": "now-15m", 244 | "to": "now" 245 | }, 246 | "timepicker": { 247 | "refresh_intervals": [ 248 | "5s", 249 | "10s", 250 | "30s", 251 | "1m", 252 | "5m", 253 | "15m", 254 | "30m", 255 | "1h", 256 | "2h", 257 | "1d" 258 | ] 259 | }, 260 | "timezone": "", 261 | "title": "L3af Rate Limiting", 262 | "uid": "yRqRsc2Mz", 263 | "version": 7 264 | } 265 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/exp_output_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "host_name": "l3af-test-host", 3 | "iface": "ibpfbr", 4 | "ipv4_address": "192.168.15.80", 5 | "bpf_programs": { 6 | "xdp_ingress": [ 7 | { 8 | "id": 0, 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "cmd_start": "", 14 | "cmd_stop": "", 15 | "cmd_status": "", 16 | "cmd_config": "", 17 | "cmd_update": "", 18 | "version": "latest", 19 | "user_program_daemon": false, 20 | "is_plugin": false, 21 | "cpu": 0, 22 | "memory": 0, 23 | "admin_status": "enabled", 24 | "prog_type": "xdp", 25 | "rules_file": "", 26 | "rules": "", 27 | "config_file_path": "", 28 | "cfg_version": 1, 29 | "start_args": null, 30 | "stop_args": null, 31 | "status_args": null, 32 | "update_args": null, 33 | "map_args": [ 34 | { 35 | "name": "rl_ports_map", 36 | "args": [ 37 | { 38 | "key": 8080, 39 | "value": 1 40 | }, 41 | { 42 | "key": 8081, 43 | "value": 1 44 | } 45 | ] 46 | }, 47 | { 48 | "name": "rl_config_map", 49 | "args": [ 50 | { 51 | "key": 0, 52 | "value": 2 53 | } 54 | ] 55 | } 56 | ], 57 | "config_args": null, 58 | "monitor_maps": [ 59 | { 60 | "name": "rl_drop_count_map", 61 | "key": 0, 62 | "aggregator": "scalar" 63 | }, 64 | { 65 | "name": "rl_recv_count_map", 66 | "key": 0, 67 | "aggregator": "max-rate" 68 | } 69 | ], 70 | "ebpf_package_repo_url": "", 71 | "object_file": "ratelimiting.bpf.o", 72 | "entry_function_name": "_xdp_ratelimiting" 73 | }, 74 | { 75 | "id": 0, 76 | "name": "connection-limit", 77 | "seq_id": 2, 78 | "artifact": "l3af_connection_limit.tar.gz", 79 | "map_name": "xdp_cl_ingress_next_prog", 80 | "cmd_start": "connection_limit", 81 | "cmd_stop": "", 82 | "cmd_status": "", 83 | "cmd_config": "", 84 | "cmd_update": "", 85 | "version": "latest", 86 | "user_program_daemon": false, 87 | "is_plugin": false, 88 | "cpu": 0, 89 | "memory": 0, 90 | "admin_status": "enabled", 91 | "prog_type": "xdp", 92 | "rules_file": "", 93 | "rules": "", 94 | "config_file_path": "", 95 | "cfg_version": 1, 96 | "start_args": null, 97 | "stop_args": null, 98 | "status_args": null, 99 | "update_args": null, 100 | "map_args": [ 101 | { 102 | "name": "cl_tcp_conns", 103 | "args": [ 104 | { 105 | "key": 8080, 106 | "value": 1 107 | }, 108 | { 109 | "key": 8081, 110 | "value": 1 111 | } 112 | ] 113 | }, 114 | { 115 | "name": "cl_max_conn", 116 | "args": [ 117 | { 118 | "key": 0, 119 | "value": 2 120 | } 121 | ] 122 | } 123 | ], 124 | "config_args": null, 125 | "monitor_maps": [ 126 | { 127 | "name": "cl_recv_count_map", 128 | "key": 0, 129 | "aggregator": "scalar" 130 | }, 131 | { 132 | "name": "cl_drop_count_map", 133 | "key": 0, 134 | "aggregator": "scalar" 135 | }, 136 | { 137 | "name": "cl_conn_count", 138 | "key": 0, 139 | "aggregator": "scalar" 140 | } 141 | ], 142 | "ebpf_package_repo_url": "", 143 | "object_file": "connection_limit.bpf.o", 144 | "entry_function_name": "_xdp_limit_conn" 145 | } 146 | ], 147 | "tc_ingress": [ 148 | { 149 | "id": 0, 150 | "name": "ipfix-flow-exporter", 151 | "seq_id": 1, 152 | "artifact": "l3af_bpf_ipfix.tar.gz", 153 | "map_name": "ipfix_ingress_jmp_table", 154 | "cmd_start": "bpf_ipfix_ingress", 155 | "cmd_stop": "", 156 | "cmd_status": "", 157 | "cmd_config": "", 158 | "cmd_update": "", 159 | "version": "latest", 160 | "user_program_daemon": true, 161 | "is_plugin": false, 162 | "cpu": 0, 163 | "memory": 0, 164 | "admin_status": "enabled", 165 | "prog_type": "tc", 166 | "rules_file": "", 167 | "rules": "", 168 | "config_file_path": "", 169 | "cfg_version": 1, 170 | "start_args": { 171 | "collector_ip": "127.0.0.1", 172 | "collector_port": "49280", 173 | "verbose": "2" 174 | }, 175 | "stop_args": null, 176 | "status_args": null, 177 | "update_args": null, 178 | "map_args": null, 179 | "config_args": null, 180 | "monitor_maps": null, 181 | "ebpf_package_repo_url": "", 182 | "object_file": "bpf_ipfix_ingress.bpf.o", 183 | "entry_function_name": "_ingress_flow_monitoring" 184 | } 185 | ], 186 | "tc_egress": [ 187 | { 188 | "id": 0, 189 | "name": "ipfix-flow-exporter", 190 | "seq_id": 1, 191 | "artifact": "l3af_bpf_ipfix.tar.gz", 192 | "map_name": "ipfix_egress_jmp_table", 193 | "cmd_start": "bpf_ipfix_egress", 194 | "cmd_stop": "", 195 | "cmd_status": "", 196 | "cmd_config": "", 197 | "cmd_update": "", 198 | "version": "latest", 199 | "user_program_daemon": true, 200 | "is_plugin": false, 201 | "cpu": 0, 202 | "memory": 0, 203 | "admin_status": "enabled", 204 | "prog_type": "tc", 205 | "rules_file": "", 206 | "rules": "", 207 | "config_file_path": "", 208 | "cfg_version": 1, 209 | "start_args": { 210 | "collector_ip": "127.0.0.1", 211 | "collector_port": "49280", 212 | "verbose": "2" 213 | }, 214 | "stop_args": null, 215 | "status_args": null, 216 | "update_args": null, 217 | "map_args": null, 218 | "config_args": null, 219 | "monitor_maps": null, 220 | "ebpf_package_repo_url": "", 221 | "object_file": "bpf_ipfix_egress.bpf.o", 222 | "entry_function_name": "_egress_flow_monitoring" 223 | } 224 | ], 225 | "probes": null 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/exp_output_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "host_name": "l3af-test-host", 3 | "iface": "ibpfbr", 4 | "ipv4_address": "192.168.15.80", 5 | "bpf_programs": { 6 | "xdp_ingress": [ 7 | { 8 | "id": 0, 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "cmd_start": "", 14 | "cmd_stop": "", 15 | "cmd_status": "", 16 | "cmd_config": "", 17 | "cmd_update": "", 18 | "version": "latest", 19 | "user_program_daemon": false, 20 | "is_plugin": false, 21 | "cpu": 0, 22 | "memory": 0, 23 | "admin_status": "enabled", 24 | "prog_type": "xdp", 25 | "rules_file": "", 26 | "rules": "", 27 | "config_file_path": "", 28 | "cfg_version": 1, 29 | "start_args": null, 30 | "stop_args": null, 31 | "status_args": null, 32 | "update_args": null, 33 | "map_args": [ 34 | { 35 | "name": "rl_ports_map", 36 | "args": [ 37 | { 38 | "key": 8080, 39 | "value": 1 40 | }, 41 | { 42 | "key": 8081, 43 | "value": 1 44 | } 45 | ] 46 | }, 47 | { 48 | "name": "rl_config_map", 49 | "args": [ 50 | { 51 | "key": 0, 52 | "value": 2 53 | } 54 | ] 55 | } 56 | ], 57 | "config_args": null, 58 | "monitor_maps": [ 59 | { 60 | "name": "rl_drop_count_map", 61 | "key": 0, 62 | "aggregator": "scalar" 63 | }, 64 | { 65 | "name": "rl_recv_count_map", 66 | "key": 0, 67 | "aggregator": "max-rate" 68 | } 69 | ], 70 | "ebpf_package_repo_url": "", 71 | "object_file": "ratelimiting.bpf.o", 72 | "entry_function_name": "_xdp_ratelimiting" 73 | }, 74 | { 75 | "id": 0, 76 | "name": "connection-limit", 77 | "seq_id": 2, 78 | "artifact": "l3af_connection_limit.tar.gz", 79 | "map_name": "xdp_cl_ingress_next_prog", 80 | "cmd_start": "connection_limit", 81 | "cmd_stop": "", 82 | "cmd_status": "", 83 | "cmd_config": "", 84 | "cmd_update": "", 85 | "version": "latest", 86 | "user_program_daemon": false, 87 | "is_plugin": false, 88 | "cpu": 0, 89 | "memory": 0, 90 | "admin_status": "enabled", 91 | "prog_type": "xdp", 92 | "rules_file": "", 93 | "rules": "", 94 | "config_file_path": "", 95 | "cfg_version": 1, 96 | "start_args": null, 97 | "stop_args": null, 98 | "status_args": null, 99 | "update_args": null, 100 | "map_args": [ 101 | { 102 | "name": "cl_tcp_conns", 103 | "args": [ 104 | { 105 | "key": 8080, 106 | "value": 1 107 | }, 108 | { 109 | "key": 8081, 110 | "value": 1 111 | } 112 | ] 113 | }, 114 | { 115 | "name": "cl_max_conn", 116 | "args": [ 117 | { 118 | "key": 0, 119 | "value": 5 120 | } 121 | ] 122 | } 123 | ], 124 | "config_args": null, 125 | "monitor_maps": [ 126 | { 127 | "name": "cl_recv_count_map", 128 | "key": 0, 129 | "aggregator": "scalar" 130 | }, 131 | { 132 | "name": "cl_drop_count_map", 133 | "key": 0, 134 | "aggregator": "scalar" 135 | }, 136 | { 137 | "name": "cl_conn_count", 138 | "key": 0, 139 | "aggregator": "scalar" 140 | } 141 | ], 142 | "ebpf_package_repo_url": "", 143 | "object_file": "connection_limit.bpf.o", 144 | "entry_function_name": "_xdp_limit_conn" 145 | } 146 | ], 147 | "tc_ingress": [ 148 | { 149 | "id": 0, 150 | "name": "ipfix-flow-exporter", 151 | "seq_id": 1, 152 | "artifact": "l3af_bpf_ipfix.tar.gz", 153 | "map_name": "ipfix_ingress_jmp_table", 154 | "cmd_start": "bpf_ipfix_ingress", 155 | "cmd_stop": "", 156 | "cmd_status": "", 157 | "cmd_config": "", 158 | "cmd_update": "", 159 | "version": "latest", 160 | "user_program_daemon": true, 161 | "is_plugin": false, 162 | "cpu": 0, 163 | "memory": 0, 164 | "admin_status": "enabled", 165 | "prog_type": "tc", 166 | "rules_file": "", 167 | "rules": "", 168 | "config_file_path": "", 169 | "cfg_version": 1, 170 | "start_args": { 171 | "collector_ip": "127.0.0.1", 172 | "collector_port": "49280", 173 | "verbose": "2" 174 | }, 175 | "stop_args": null, 176 | "status_args": null, 177 | "update_args": null, 178 | "map_args": null, 179 | "config_args": null, 180 | "monitor_maps": null, 181 | "ebpf_package_repo_url": "", 182 | "object_file": "bpf_ipfix_ingress.bpf.o", 183 | "entry_function_name": "_ingress_flow_monitoring" 184 | } 185 | ], 186 | "tc_egress": [ 187 | { 188 | "id": 0, 189 | "name": "ipfix-flow-exporter", 190 | "seq_id": 1, 191 | "artifact": "l3af_bpf_ipfix.tar.gz", 192 | "map_name": "ipfix_egress_jmp_table", 193 | "cmd_start": "bpf_ipfix_egress", 194 | "cmd_stop": "", 195 | "cmd_status": "", 196 | "cmd_config": "", 197 | "cmd_update": "", 198 | "version": "latest", 199 | "user_program_daemon": true, 200 | "is_plugin": false, 201 | "cpu": 0, 202 | "memory": 0, 203 | "admin_status": "enabled", 204 | "prog_type": "tc", 205 | "rules_file": "", 206 | "rules": "", 207 | "config_file_path": "", 208 | "cfg_version": 1, 209 | "start_args": { 210 | "collector_ip": "127.0.0.1", 211 | "collector_port": "49280", 212 | "verbose": "2" 213 | }, 214 | "stop_args": null, 215 | "status_args": null, 216 | "update_args": null, 217 | "map_args": null, 218 | "config_args": null, 219 | "monitor_maps": null, 220 | "ebpf_package_repo_url": "", 221 | "object_file": "bpf_ipfix_egress.bpf.o", 222 | "entry_function_name": "_egress_flow_monitoring" 223 | } 224 | ], 225 | "probes": null 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/exp_output_4.json: -------------------------------------------------------------------------------- 1 | { 2 | "host_name": "l3af-test-host", 3 | "iface": "ibpfbr", 4 | "ipv4_address": "192.168.15.80", 5 | "bpf_programs": { 6 | "xdp_ingress": [ 7 | { 8 | "id": 0, 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "cmd_start": "", 14 | "cmd_stop": "", 15 | "cmd_status": "", 16 | "cmd_config": "", 17 | "cmd_update": "", 18 | "version": "latest", 19 | "user_program_daemon": false, 20 | "is_plugin": false, 21 | "cpu": 0, 22 | "memory": 0, 23 | "admin_status": "enabled", 24 | "prog_type": "xdp", 25 | "rules_file": "", 26 | "rules": "", 27 | "config_file_path": "", 28 | "cfg_version": 1, 29 | "start_args": null, 30 | "stop_args": null, 31 | "status_args": null, 32 | "update_args": null, 33 | "map_args": [ 34 | { 35 | "name": "rl_ports_map", 36 | "args": [ 37 | { 38 | "key": 8080, 39 | "value": 1 40 | }, 41 | { 42 | "key": 8081, 43 | "value": 1 44 | } 45 | ] 46 | }, 47 | { 48 | "name": "rl_config_map", 49 | "args": [ 50 | { 51 | "key": 0, 52 | "value": 2 53 | } 54 | ] 55 | } 56 | ], 57 | "config_args": null, 58 | "monitor_maps": [ 59 | { 60 | "name": "rl_drop_count_map", 61 | "key": 0, 62 | "aggregator": "scalar" 63 | }, 64 | { 65 | "name": "rl_recv_count_map", 66 | "key": 0, 67 | "aggregator": "max-rate" 68 | } 69 | ], 70 | "ebpf_package_repo_url": "", 71 | "object_file": "ratelimiting.bpf.o", 72 | "entry_function_name": "_xdp_ratelimiting" 73 | }, 74 | { 75 | "id": 0, 76 | "name": "connection-limit", 77 | "seq_id": 2, 78 | "artifact": "l3af_connection_limit.tar.gz", 79 | "map_name": "xdp_cl_ingress_next_prog", 80 | "cmd_start": "connection_limit", 81 | "cmd_stop": "", 82 | "cmd_status": "", 83 | "cmd_config": "", 84 | "cmd_update": "", 85 | "version": "latest", 86 | "user_program_daemon": false, 87 | "is_plugin": false, 88 | "cpu": 0, 89 | "memory": 0, 90 | "admin_status": "enabled", 91 | "prog_type": "xdp", 92 | "rules_file": "", 93 | "rules": "", 94 | "config_file_path": "", 95 | "cfg_version": 1, 96 | "start_args": null, 97 | "stop_args": null, 98 | "status_args": null, 99 | "update_args": null, 100 | "map_args": [ 101 | { 102 | "name": "cl_tcp_conns", 103 | "args": [ 104 | { 105 | "key": 8080, 106 | "value": 1 107 | }, 108 | { 109 | "key": 8081, 110 | "value": 1 111 | } 112 | ] 113 | }, 114 | { 115 | "name": "cl_max_conn", 116 | "args": [ 117 | { 118 | "key": 0, 119 | "value": 5 120 | } 121 | ] 122 | } 123 | ], 124 | "config_args": null, 125 | "monitor_maps": [ 126 | { 127 | "name": "cl_recv_count_map", 128 | "key": 0, 129 | "aggregator": "scalar" 130 | }, 131 | { 132 | "name": "cl_drop_count_map", 133 | "key": 0, 134 | "aggregator": "scalar" 135 | }, 136 | { 137 | "name": "cl_conn_count", 138 | "key": 0, 139 | "aggregator": "scalar" 140 | } 141 | ], 142 | "ebpf_package_repo_url": "", 143 | "object_file": "connection_limit.bpf.o", 144 | "entry_function_name": "_xdp_limit_conn" 145 | } 146 | ], 147 | "tc_ingress": [ 148 | { 149 | "id": 0, 150 | "name": "traffic-mirroring", 151 | "seq_id": 2, 152 | "artifact": "l3af_traffic_mirroring.tar.gz", 153 | "map_name": "mirroring_ingress_jmp_table", 154 | "cmd_start": "mirroring", 155 | "cmd_stop": "", 156 | "cmd_status": "", 157 | "cmd_config": "", 158 | "cmd_update": "", 159 | "version": "latest", 160 | "user_program_daemon": false, 161 | "is_plugin": false, 162 | "cpu": 0, 163 | "memory": 0, 164 | "admin_status": "enabled", 165 | "prog_type": "tc", 166 | "rules_file": "", 167 | "rules": "", 168 | "config_file_path": "", 169 | "cfg_version": 1, 170 | "start_args": { 171 | "dst-port": "8080", 172 | "protocol": "tcp,icmp", 173 | "redirect-to": "lo", 174 | "src-address": "0.0.0.0", 175 | "src-port": "0", 176 | "tunnel-interface-name": "gue1", 177 | "tunnel-local-port": "6080", 178 | "tunnel-remote-address": "127.0.0.1", 179 | "tunnel-remote-port": "6081" 180 | }, 181 | "stop_args": null, 182 | "status_args": null, 183 | "update_args": null, 184 | "map_args": null, 185 | "config_args": null, 186 | "monitor_maps": null, 187 | "ebpf_package_repo_url": "", 188 | "object_file": "mirroring_ingress.bpf.o", 189 | "entry_function_name": "_ingress_redirect" 190 | } 191 | ], 192 | "tc_egress": [ 193 | { 194 | "id": 0, 195 | "name": "traffic-mirroring", 196 | "seq_id": 2, 197 | "artifact": "l3af_traffic_mirroring.tar.gz", 198 | "map_name": "mirroring_egress_jmp_table", 199 | "cmd_start": "mirroring", 200 | "cmd_stop": "", 201 | "cmd_status": "", 202 | "cmd_config": "", 203 | "cmd_update": "", 204 | "version": "latest", 205 | "user_program_daemon": false, 206 | "is_plugin": false, 207 | "cpu": 0, 208 | "memory": 0, 209 | "admin_status": "enabled", 210 | "prog_type": "tc", 211 | "rules_file": "", 212 | "rules": "", 213 | "config_file_path": "", 214 | "cfg_version": 1, 215 | "start_args": { 216 | "dst-address": "0.0.0.0", 217 | "dst-port": "0", 218 | "protocol": "tcp,icmp", 219 | "redirect-to": "lo", 220 | "src-port": "0", 221 | "tunnel-interface-name": "gue1", 222 | "tunnel-local-port": "6080", 223 | "tunnel-remote-address": "127.0.0.1", 224 | "tunnel-remote-port": "6081" 225 | }, 226 | "stop_args": null, 227 | "status_args": null, 228 | "update_args": null, 229 | "map_args": null, 230 | "config_args": null, 231 | "monitor_maps": null, 232 | "ebpf_package_repo_url": "", 233 | "object_file": "mirroring_egress.bpf.o", 234 | "entry_function_name": "_egress_redirect" 235 | } 236 | ], 237 | "probes": null 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /discussions/secure_web_api.md: -------------------------------------------------------------------------------- 1 | # L3AFD Secure web API 2 | 3 | ## Overview 4 | 5 | Walmart developed L3AF to simplify the management and orchestration of multiple eBPF programs in an enterprise 6 | environment. 7 | 8 | L3AF’s control plane consists of multiple components that work together to orchestrate eBPF programs: 9 | 10 | - L3AF Daemon (L3AFD), which runs on each node where eBPF program runs. L3AFD reads configuration data and manages 11 | the execution and monitoring of eBPF programs running on the node. 12 | - Deployment HTTP APIs exposed by L3AFD, which a user calls to generate configuration data. This configuration data 13 | includes which eBPF programs will run, their execution order, and the configuration arguments for each eBPF program. 14 | - A database and local key/value (KV) store that stores the configuration data. 15 | - A datastore that stores eBPF program artifacts (e.g., byte code and/or native code). 16 | 17 | When users want to deploy an eBPF program, they can use an app to call the L3AFD API with appropriate parameters. 18 | This request would generate a new config (KV pair). Once L3AFD reads this new config, it orchestrates eBPF programs on 19 | the host as per the defined parameters. If the user gives a set of eBPF programs, then L3AFD can orchestrate all of 20 | them in the sequence that the user wanted (aka chaining). 21 | 22 | ## Need for secure web APIs 23 | 24 | L3AFD currently uses the Go HTTP client to download the configured eBPF packages from a datastore (package repository). 25 | However, this client does not support yet TLS, but we are investigating how best to support TLS. In the open-source 26 | world, users will presumably expect to be able to use TLS in this situation. This is also an early step toward using 27 | a secure eBPF Package Repository (https://github.com/l3af-project/l3afd/issues/2). 28 | 29 | L3AFD has an HTTP API that can be used to configure the eBPF programs. However, this API only supports HTTP. 30 | This works for a use case where the L3AFD API is called only from the localhost, but this is probably unintuitive. 31 | In the future, we would like to come up with service that can call the L3AFD APIs remotely. For this, we could leverage 32 | mTLS for a mutually secure connection between the client and server. Also, new open-source adopters of L3AF will presumably 33 | want to avoid calling the L3AFD API locally on each node (https://github.com/l3af-project/l3afd/issues/4). 34 | 35 | ## Types of certificates are supported 36 | 37 | The TLS protocol aims primarily to provide cryptography, including privacy (confidentiality), integrity, and 38 | authenticity through certificates, between L3AFD and client's communication. These certificates can be issued by a 39 | third-party trusted authority (i.e., IdenTrust, DigiCert, Sectigo, etc), and we can create self-signed certificates 40 | using tools like ```openssl```. 41 | 42 | This completely depends on the users, whether to use Trusted CA certificates or self-signed certificates. L3AF will not 43 | provide any certificates. 44 | 45 | ## L3AF deployment scenarios 46 | 47 | L3AF could be running in two scenarios, users can use L3AF in secure enterprise private networks and in public networks. 48 | In the case of a private network, L3AFD and clients will be communicating with each other over a network that is normally 49 | protected by vpn or PCI (Payment Card Information), and hence some may not consider it essential to enable mTLS in this 50 | case, although the current industry trend and best practice is to consider it essential even on private networks, which 51 | trend uses the [Zero trust security model](https://en.wikipedia.org/wiki/Zero_trust_security_model). 52 | 53 | However, in the case of a public network, clients will be communicating with L3AFD over insecure networks. L3AF wants to 54 | secure its endpoints using industry's best standard available solutions. This can be configured from l3afd’s config file. 55 | 56 | ## Enabling mTLS for L3AFD 57 | 58 | L3AFD (L3AF Daemon) will require a set of root certificates (root.crt and root.key) and a pair of server certificates 59 | (server.crt and server.key) to accept remote connections. L3AFD will check for these certificates, and in case these are 60 | not found, L3AFD will stop with error ```certificates are not found```. 61 | 62 | The client will require a pair of client certificates (client.crt and client.key), generated from the same root 63 | certificates from which the server certificates have been generated, and the public root certificate (root.crt) to 64 | communicate with L3AFD. 65 | 66 | Process to enable mTLS 67 | - [Provision of Certificates](#provision-of-certificates) 68 | - [Location of Certificates](#location-of-certificates) 69 | - [Enable mTLS](#enabling-mtls) 70 | 71 | ### Provision of Certificates 72 | 73 | As mentioned before, users can use already pre-existing certificates. L3AF will not provide any certificates. 74 | 75 | ### Location of Certificates 76 | 77 | The default location for the certificates and the path can also be changed through a l3afd configuration option 78 | in cases where the user would like to use a custom location. 79 | 80 | The user will have to place the root certificates and the server certificates in the configured directory path before 81 | starting L3AFD. 82 | 83 | ### Enabling mTLS 84 | 85 | A flag will be provided in l3afd.cfg which enables mTLS by default. L3AFD will not accept remote connections 86 | without TLS by default. 87 | 88 | ## Minimum TLS version 89 | 90 | The TLS versions popularly supported in the market are v1.2 and v1.3. L3AF can support v1.3 by default and require configuration 91 | to allow downgrading security. 92 | 93 | ## L3AFD Web API Listening Interface 94 | 95 | L3AFD can be configured to listen on IP addresses / interfaces other than localhost. 96 | There could be an additional check to only accept traffic from the specified FQDN (Host header) or SNI if TLS. 97 | 98 | ## Monitoring of certificates 99 | 100 | L3AFD will be monitoring for expiration of the certificates on regular basis (e.g., every 24 hours) and it will start 101 | logging warnings before a certain period (30 days) of expiration date. If the certificates are not renewed before 102 | expiration, L3AFD will stop with error ```certificates are expired, replace new pair of certificates```. 103 | It is users' responsibility to replace old certificates with new pair certificates. L3AFD loads the new 104 | certificates automatically, and it does not require a restart. 105 | 106 | L3AFD can also expose metrics for the certificate expiration status and certificate errors. 107 | 108 | ## Token-based authentication 109 | 110 | In this approach OAuth2 token used for authenticating the client. Here, clients should acquire tokens from the identity 111 | management service. Every request will have a metadata component which carries the token. L3AFD will verify the token with 112 | the configured identity management service and if the token is valid it will then accept the request. 113 | 114 | ## Authorization 115 | 116 | Authorization is a security mechanism that verifies the clients have sufficient permissions to perform any CRUD actions 117 | on config resources. RBAC determines client privileges to update the configs on the node and enables access controls 118 | based on granted roles. Initially there will admin and user roles. 119 | - Admin - Full permission to create, update, read, and delete any configuration element through the API 120 | - Read-Only - Permission to read configuration elements through the API 121 | -------------------------------------------------------------------------------- /discussions/chaining_enhancements.md: -------------------------------------------------------------------------------- 1 | # Ideas for Simplifying eBPF program chaining 2 | 3 | The purpose of this document is to discuss 4 | 1) why we do eBPF program chaining, 5 | 2) how chaining is implemented currently in L3AF, and 6 | 3) ideas and plans for chaining enhancements. 7 | 8 | We encourage the open source community to be involved with all phases of planning and implementation. 9 | 10 | # Introduction 11 | 12 | ## What is eBPF program chaining 13 | 14 | eBPF program chaining is the procedure of calling multiple eBPF programs in a sequence. In the case of network eBPF programs, only a single eBPF program can be attached to the network interface for each type (i.e., TC and XDP). We can, however, sequentially execute multiple eBPF programs per type by having eBPF programs call the next program in the chain. 15 | 16 | ## Why do we chain eBPF programs? 17 | 18 | This is maybe the most common question we get about L3AFD. To understand the answer, it's important to understand one of the core philosophies of L3AF: L3AF is a platform to orchestrate and compose multiple, independent eBPF programs. We believe that eBPF users can benefit from the development and open distribution of modular eBPF programs. In this respect, we embrace the Unix philosophy of “write programs that do one thing and do it well.” Our vision is that the L3AF team, open-source community, and other businesses will develop independent eBPF programs that will be shared in a “eBPF Package Repository.” Users can then download a selection of signed eBPF programs and orchestrate them to solve their unique business needs. 19 | 20 | As an example, in one datacenter you may want to run this chain of programs: 21 | 22 | `rate limiter` -> `connection limiter` -> `traffic mirroring` 23 | 24 | However, in another datacenter, you may want to this chain: 25 | 26 | `rate limiter` -> `connection limiter` -> `load balancer` 27 | 28 | Chaining together eBPF programs is the key feature that empowers users to compose different, independent programs together to solve those unique business needs. 29 | 30 | ## How is chaining done today? 31 | 32 | Chaining in L3AF today is done using the `bpf_tail_call` BPF helper function (see `bpf-helpers(7)`). The `bpf_tail_call` function is called at the end of each eBPF kernel program. However, for chaining to be most useful, we must not hard code the next program in the chain; we want that to be dynamic so that programs in the chain can be added, removed, or reordered on-the-fly. This dynamic chaining is accomplished by using eBPF maps to store and retrieve the next eBPF program file descriptor (FD) in the chain. In L3AF, the order of operations goes like this: 1) each eBPF program creates a map where the FD of the next program should be stored, 2) the next program in the chain writes its FD to the map of the previous eBPF program, and 3) a previous kernel eBPF program runs and before finishing reads the FD to the next kernel eBPF program and executes it with a `bpf_tail_call`. 33 | 34 | Here is a visual representation: 35 | 36 | ![L3AF_eBPF_chaining](https://user-images.githubusercontent.com/146526/140865148-995a0578-eaef-456c-832b-83ababa6484e.png) 37 | 38 | # Problem Statement 39 | 40 | Our current chaining approach is functional (and similar approaches are used in other projects). However, there is one issue that puts the current approach at odds with our long term vision for truly independent and modular eBPF programs. 41 | 42 | The problem with the current approach is that it requires each eBPF program be aware that it is part of a chain of programs. More specifically, each eBPF program must contain a nontrivial amount of logic to manage itself in the chain and also call the next program in the chain. 43 | 44 | For example, the userspace eBPF program must write its FD to the previous eBPF program's map: 45 | 46 | ```c 47 | /* Get the previous program's map fd in the chain */ 48 | int prev_prog_map_fd = bpf_obj_get(prev_prog_map); 49 | if (prev_prog_map_fd < 0) { 50 | log_err("Failed to fetch previous xdp function in the chain"); 51 | exit(EXIT_FAILURE); 52 | } 53 | /* Update current prog fd in the last prog map fd, 54 | * so it can chain the current one */ 55 | if(bpf_map_update_elem(prev_prog_map_fd, &pkey, &(prog_fd[0]), 0)) { 56 | log_err("Failed to update prog fd in the chain"); 57 | exit(EXIT_FAILURE); 58 | } 59 | ``` 60 | 61 | And the kernel eBPF program must do perform the `bpf_tail_call` to the next program: 62 | 63 | ```c 64 | /* Maintains the prog fd of the next XDP program in the chain */ 65 | struct bpf_map_def SEC("maps") xdp_rl_ingress_next_prog = { 66 | .type = BPF_MAP_TYPE_PROG_ARRAY, 67 | .key_size = sizeof(int), 68 | .value_size = sizeof(int), 69 | .max_entries = 1 70 | }; 71 | 72 | // ... 73 | 74 | bpf_tail_call(ctx, &xdp_rl_ingress_next_prog, 0); 75 | ``` 76 | 77 | In addition to these snippets, there is other chain-related code and state that are required for each ePBF program. Ideally, we want to move all chain related policy and code up the stack and into L3AFD, such that the individual eBPF programs don't require any code specific to chaining. Doing so would accomplish the following project goals: 78 | 79 | 1. eBPF programs become truly independent and modular 80 | 2. Developers of eBPF programs don't need to implement any "special" logic or boilerplate in their program 81 | 3. The eBPF Package Repository becomes an easier place to contribute to because eBPF programs don't require chaining logic 82 | 83 | # Proposed Solution 84 | 85 | ## Kernel >= 5.10 86 | 87 | ### XDP 88 | 89 | As of Linux kernel 5.10, the kernel and libxdp have the ability to chain eBPF programs using a multi-program "dispatcher." A formal specification for doing so is found [here](https://github.com/xdp-project/xdp-tools/blob/master/lib/libxdp/protocol.org). This would allow for L3AF to completely manage the chaining of eBPF programs that do not require any chain-specific logic themselves. However, in order for this to happen, a Go libxdp implementation is needed. 90 | 91 | Visually, this proposed solution would look like this: 92 | 93 | ![L3AF_xdp_dispatcher_chaining](https://user-images.githubusercontent.com/146526/140865168-f51a40a9-d664-443d-ada1-18f1348311fb.png) 94 | 95 | L3AFD would interface directly with libxdp to set the execution order of the eBPF kernel programs. 96 | 97 | Userspace eBPF programs could still be run to interface with their respective kernel programs. We would like to migrate these userspace programs from C to Go (now that there are good Go eBPF libraries available), but that migration is beyond the scope of this document. 98 | 99 | ### TC 100 | 101 | Similar to XDP, TC already has its own mechanisms for chaining TC eBPF programs without the need for chain-specific logic in the eBPF programs. In fact, using these capabilities does not require Linux Kernel >= 5.10 (presumably, the TC chaining capabilities have been available much longer). However, we believe it would make sense to migrate away from `bpf_tail_call` at the same time for both TC and XDP. The reason for this belief is that one benefit of `bpf_tail_call` is that it works the same for both TC and XDP--if we're going to use it for one, we might as well use it for the other; we don't reap the true benefit unless we completely remove the need for chain-specific logic in all eBPF programs. 102 | 103 | The TC tooling is relatively complex and more testing is needed to confirm the exact TC-based approach, but chaining should look like this: 104 | 105 | ```bash 106 | # tc filter replace dev em1 ingress prio 1 handle 1 bpf da obj prog1.o 107 | # tc filter replace dev em1 ingress prio 2 handle 1 bpf da obj prog2.o 108 | ``` 109 | 110 | (Ideally we would call into a library instead of running `tc` directly) 111 | 112 | ## Kernels < 5.10 113 | 114 | For kernels that do not support the libxdp dispatcher, we plan to continue to use `bpf_tail_call` and simply phase it out over time. However, there are some improvements we could make to this existing approach: 115 | 116 | 1. Automate the injection of the necessary boilerplate code for chaining via `bpf_tail_call`. 117 | 2. Consolidate our usage of multiple chaining maps into a single map (per eBPF program type) that can be replaced atomically. We believe this is the approach Cilium uses, for example. 118 | 119 | ## Phase 1 Solution - 120 | 121 | Decouple the chaining logic from eBPF programs. 122 | 123 | ![L3AF_decouple_chaining](https://user-images.githubusercontent.com/7508744/216295926-e05d55ec-33d8-48b6-8783-b5b02a28f3da.png) 124 | 125 | This approach will work for program type XDP and TC with cross-platform support. This will not support atomic updates. 126 | -------------------------------------------------------------------------------- /discussions/prog_repo.md: -------------------------------------------------------------------------------- 1 | # L3AF eBPF Package Repository 2 | 3 | The concept of a L3AF eBPF Package Repository is to create a location where 4 | eBPF Programs from any trusted party can be uploaded and made available for others to download. 5 | 6 | In the context of L3AF, we define an eBPF Package as a kernel space program with 7 | an optional, cooperative user space program. 8 | 9 | # What should we name it 10 | 11 | "eBPF Package Repository" is the name that has been chosen by the Technical Steering Committee. 12 | 13 | # Is the eBPF Package Repository part of the L3AF Project 14 | 15 | Firstly, we define the "L3AF Project" as the L3AF open-source project that exists 16 | within The Linux Foundation. When we say "L3AF", we are referring to the entire L3AF Project. 17 | This is not to be confused with: 18 | 19 | - The `l3af-project` GitHub organization 20 | - The L3AFD daemon, which is a major component of the L3AF Project. 21 | 22 | We consider L3AF to be an entire ecosystem that aims to provide eBPF Programs as a service. 23 | We've otherwise phrased this as "complete lifecycle management of eBPF programs". 24 | This definition includes: 25 | 26 | - The L3AFD daemon, an orchestrator that provides APIs to launch and manage eBPF programs on a node 27 | - The L3AF eBPF Package Repository 28 | - Programs within the eBPF Package Repository 29 | 30 | Note, however, that we have no intention of limiting the creation of other public or private 31 | eBPF Package repositories. 32 | 33 | L3AF Technical Steering Committee recognizes that it may make sense to migrate the eBPF Package Repository 34 | out of the L3AF Project and into its own Linux Foundation project in the future. 35 | Doing this initially may not make sense (due to L3AF-specific eBPF program chaining implementation 36 | for networking programs), but as L3AF and other projects mature, a platform-agnostic repository 37 | could be useful for multiple projects. 38 | 39 | # What should an initial version look like 40 | 41 | This section examines simple ways to create a location where eBPF Programs can be uploaded 42 | and made available for others to download. 43 | 44 | ## A GitHub repository may be sufficient 45 | 46 | We would like to leverage GitHub: 47 | 48 | - A new GitHub repository will be created to store eBPF program source code 49 | - All submissions will be manually reviewed by the L3AF team 50 | - Once approved, programs will be published in the eBPF Package Repository 51 | 52 | Another important thing to note is that, initially, code submissions will need 53 | to conform to L3AF's eBPF program chaining mechanics. 54 | 55 | ## To Build or Not to Build 56 | 57 | Because of the overhead and support requirements of a full build system, it may not be 58 | feasible to build the eBPF program source code in the initial version. However, we believe 59 | not being able to build from source would greatly hinder adoption from both contributors and users. 60 | Our proposal, therefore, is to have the repository’s initial version include scripts (e.g. Dockerfile 61 | for build system images), and steps to build eBPF Programs locally (e.g. for x86_64 platforms). 62 | 63 | ## eBPF Package Repository of the future 64 | 65 | Future versions could build on top of the foundation laid by the initial version. 66 | 67 | # What should a future version look like 68 | 69 | This section examines simple ways to create a location where eBPF Packages from trusted parties 70 | can be uploaded and made available for others to download. This can also enable users to provide 71 | rating, reviews, and tags to the packages. 72 | 73 | ### Build Process 74 | 75 | Contributed eBPF Packages can be built on common images for Linux and other platforms. 76 | Contributors are expected to build their code using the most recent images used by our build system. 77 | Contributors could have a choice to build on Linux only or other platforms. 78 | 79 | Build artifacts (i.e., eBPF program bytecode and user space binaries) could be stored 80 | in a public file storage repository. Users could download the artifacts directly 81 | from this repository. In fact, such a repository could also be considered the 82 | eBPF Package Repository, and the source repository could be a separate entity. 83 | 84 | ### Portability 85 | 86 | It is hard to discuss a build system without broaching the topic of portability. 87 | The eBPF portability story has improved recently with the introduction of eBPF CO-RE on Linux. 88 | Previous issues with portability and the eBPF CO-RE solution are explained here: 89 | 90 | https://nakryiko.com/posts/bpf-portability-and-co-re/ 91 | 92 | Because an eBPF Package Repository is a place from where contributed eBPF programs (byte code or native code) 93 | can be downloaded to run on a variety of kernel versions, we propose that the repository follows 94 | best practices for compatibility, such as using eBPF CO-RE for Linux. Similar best practices 95 | can be followed on non-Linux platforms as they mature and become available. 96 | The user space components of eBPF programs pose a separate, complicated portability obstacle, 97 | which is compounded by the desire of the L3AF project to support user space programs in multiple 98 | languages. For the future version of the repository, initially it should be sufficient to build 99 | (of a compiled language) and unit test for the x86_64 platform. The user space component should document 100 | any installation dependencies it has (e.g., MySQL, Grafana, Python libraries, etc.). 101 | Contributors to the repository would be responsible to provide the necessary build scripts 102 | and configuration. 103 | 104 | ### Multiple Versions 105 | 106 | Regardless of whether the package is built from source or not, eBPF programs should use semantic 107 | versioning. The repository should then host previous versions (in addition to the current version) 108 | in some reasonable manner. 109 | 110 | ### Automated Reviews 111 | 112 | There can be a mechanism to review source code, using tools to detect like code formatting errors, 113 | complexity, code issues, and code duplication. Similarly, vulnerability detection 114 | scanners can be used for artifacts before uploading. 115 | 116 | ## Alternative to Hosting and Building Source Code 117 | 118 | An alternative to the L3AF Project hosting and building contributed source code would be for 119 | contributors to submit or self-host a signed package containing their eBPF programs and any 120 | documentation. The L3AF daemon, by default, would only download and run eBPF programs signed 121 | by trusted parties. This provides a nice segue for us to go into the signing section. 122 | 123 | ## Signing and Verification 124 | 125 | There are three different layers of signing that should be discussed, the signing of the 126 | kernel eBPF program (i.e., byte code), the signing of the eBPF programs package (i.e., an archive 127 | containing the built eBPF program and any associated user space programs) and 128 | signing for Hypervisors (i.e., Virtualization-based Security). 129 | 130 | ### Signing and verifying eBPF programs 131 | 132 | There are efforts underway in the eBPF community for how to sign and verify 133 | Linux eBPF programs, this enables JIT’ed native code: 134 | 135 | https://lore.kernel.org/bpf/20211203191844.69709-1-mcroce@linux.microsoft.com/ 136 | https://linuxplumbersconf.org/event/11/contributions/947/ 137 | 138 | Similarly, signing mechanism for other platforms are also being explored. 139 | 140 | L3AF can use the best practices that are established for signing and verifying eBPF programs. 141 | 142 | ### Signing and verifying the eBPF Program package 143 | 144 | The eBPF package should be signed by using the creators trusted keys. The user should 145 | then configure L3AF to explicitly trust signed packages with the key creator used. L3AF by default 146 | will not trust signed packages by any parties. 147 | 148 | ### Signing for Hypervisors 149 | 150 | This approach needs to be explored based on hypervisor operating systems security policies. 151 | 152 | ### Define trust 153 | 154 | In this context, a trusted user and contributor is defined as an authorised user registered to the 155 | system, who has credentials to log in with RBAC restrictions. A contributor can be given access 156 | to a set of trusted keys. 157 | 158 | ### Running L3AFD in trusted mode 159 | 160 | The package can be signed by its creator using the trusted keys. 161 | L3AFD can have a mechanism to verify that the package is signed using trusted keys and loaded accordingly. 162 | 163 | ### Running L3AFD in normal mode (not trusted) 164 | 165 | L3AFD can bypass verification process before loading any eBPF programs, it is the sole responsibility of 166 | the user to verify and validate the packages. 167 | 168 | ### User Experience 169 | 170 | A priority for future versions of the repository would be to improve the user experience. 171 | 172 | Some examples: 173 | - Frontend website 174 | - Searchable 175 | - Rating system 176 | - Reviews 177 | - Buying and selling 178 | - TLS 179 | - Oauth 180 | 181 | ## Closed Source Contributions 182 | 183 | If a public eBPF Program Repository becomes popular, we can imagine that 184 | some contributors may wish to monetize their eBPF Programs. In this case, we 185 | would not be hosting and building the contributors source code, and we would be 186 | hosting only a signed package containing their eBPF Programs. 187 | 188 | eBPF licensing information can be found below. The document discusses 189 | "Packaging BPF programs with user space applications." 190 | 191 | https://www.kernel.org/doc/Documentation/bpf/bpf_licensing.rst 192 | -------------------------------------------------------------------------------- /dev_environment/cfg/grafana/dashboards/l3af_connection_limiting.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "target": { 12 | "limit": 100, 13 | "matchAny": false, 14 | "tags": [], 15 | "type": "dashboard" 16 | }, 17 | "type": "dashboard" 18 | } 19 | ] 20 | }, 21 | "editable": true, 22 | "gnetId": null, 23 | "graphTooltip": 0, 24 | "id": 2, 25 | "links": [], 26 | "panels": [ 27 | { 28 | "aliasColors": {}, 29 | "bars": false, 30 | "dashLength": 10, 31 | "dashes": false, 32 | "datasource": null, 33 | "fieldConfig": { 34 | "defaults": { 35 | "links": [] 36 | }, 37 | "overrides": [] 38 | }, 39 | "fill": 0, 40 | "fillGradient": 0, 41 | "gridPos": { 42 | "h": 8, 43 | "w": 8, 44 | "x": 0, 45 | "y": 0 46 | }, 47 | "hiddenSeries": false, 48 | "id": 8, 49 | "legend": { 50 | "alignAsTable": true, 51 | "avg": true, 52 | "current": true, 53 | "max": true, 54 | "min": false, 55 | "rightSide": false, 56 | "show": true, 57 | "sort": "current", 58 | "sortDesc": true, 59 | "total": false, 60 | "values": true 61 | }, 62 | "lines": true, 63 | "linewidth": 1, 64 | "links": [], 65 | "nullPointMode": "null", 66 | "options": { 67 | "alertThreshold": true 68 | }, 69 | "percentage": false, 70 | "pluginVersion": "8.1.5", 71 | "pointradius": 5, 72 | "points": false, 73 | "renderer": "flot", 74 | "seriesOverrides": [], 75 | "spaceLength": 10, 76 | "stack": false, 77 | "steppedLine": false, 78 | "targets": [ 79 | { 80 | "exemplar": true, 81 | "expr": "l3afd_BPFMonitorMap{map_name=\"cl_conn_count_0_scalar\",ebpf_program=\"connection-limit\"}", 82 | "hide": false, 83 | "interval": "30s", 84 | "legendFormat": "{{host}}", 85 | "refId": "A" 86 | } 87 | ], 88 | "thresholds": [], 89 | "timeFrom": null, 90 | "timeRegions": [], 91 | "timeShift": null, 92 | "title": "inbound connections", 93 | "tooltip": { 94 | "shared": true, 95 | "sort": 2, 96 | "value_type": "individual" 97 | }, 98 | "type": "graph", 99 | "xaxis": { 100 | "buckets": null, 101 | "mode": "time", 102 | "name": null, 103 | "show": true, 104 | "values": [] 105 | }, 106 | "yaxes": [ 107 | { 108 | "format": "short", 109 | "label": "Connections", 110 | "logBase": 1, 111 | "max": null, 112 | "min": "0", 113 | "show": true 114 | }, 115 | { 116 | "format": "short", 117 | "label": null, 118 | "logBase": 1, 119 | "max": null, 120 | "min": null, 121 | "show": false 122 | } 123 | ], 124 | "yaxis": { 125 | "align": false, 126 | "alignLevel": null 127 | } 128 | }, 129 | { 130 | "aliasColors": {}, 131 | "bars": false, 132 | "dashLength": 10, 133 | "dashes": false, 134 | "datasource": null, 135 | "fieldConfig": { 136 | "defaults": { 137 | "links": [] 138 | }, 139 | "overrides": [] 140 | }, 141 | "fill": 0, 142 | "fillGradient": 0, 143 | "gridPos": { 144 | "h": 7, 145 | "w": 8, 146 | "x": 8, 147 | "y": 0 148 | }, 149 | "hiddenSeries": false, 150 | "id": 9, 151 | "legend": { 152 | "alignAsTable": true, 153 | "avg": true, 154 | "current": true, 155 | "hideEmpty": true, 156 | "hideZero": true, 157 | "max": true, 158 | "min": false, 159 | "rightSide": false, 160 | "show": true, 161 | "sort": "current", 162 | "sortDesc": true, 163 | "total": false, 164 | "values": true 165 | }, 166 | "lines": true, 167 | "linewidth": 1, 168 | "links": [], 169 | "nullPointMode": "null", 170 | "options": { 171 | "alertThreshold": true 172 | }, 173 | "percentage": false, 174 | "pluginVersion": "8.1.5", 175 | "pointradius": 5, 176 | "points": false, 177 | "renderer": "flot", 178 | "seriesOverrides": [], 179 | "spaceLength": 10, 180 | "stack": false, 181 | "steppedLine": false, 182 | "targets": [ 183 | { 184 | "exemplar": true, 185 | "expr": "sum(irate(l3afd_BPFMonitorMap{map_name=\"cl_recv_count_map_0_scalar\", ebpf_program=\"connection-limit\"}[2m])) by (host)", 186 | "hide": false, 187 | "interval": "30s", 188 | "legendFormat": "{{host}}", 189 | "refId": "A" 190 | } 191 | ], 192 | "thresholds": [], 193 | "timeFrom": null, 194 | "timeRegions": [], 195 | "timeShift": null, 196 | "title": "recv connections", 197 | "tooltip": { 198 | "shared": true, 199 | "sort": 2, 200 | "value_type": "individual" 201 | }, 202 | "type": "graph", 203 | "xaxis": { 204 | "buckets": null, 205 | "mode": "time", 206 | "name": null, 207 | "show": true, 208 | "values": [] 209 | }, 210 | "yaxes": [ 211 | { 212 | "format": "short", 213 | "label": "conn / sec", 214 | "logBase": 1, 215 | "max": null, 216 | "min": "0", 217 | "show": true 218 | }, 219 | { 220 | "format": "short", 221 | "label": null, 222 | "logBase": 1, 223 | "max": null, 224 | "min": null, 225 | "show": false 226 | } 227 | ], 228 | "yaxis": { 229 | "align": false, 230 | "alignLevel": null 231 | } 232 | }, 233 | { 234 | "aliasColors": {}, 235 | "bars": false, 236 | "dashLength": 10, 237 | "dashes": false, 238 | "datasource": null, 239 | "fieldConfig": { 240 | "defaults": { 241 | "links": [] 242 | }, 243 | "overrides": [] 244 | }, 245 | "fill": 0, 246 | "fillGradient": 0, 247 | "gridPos": { 248 | "h": 7, 249 | "w": 8, 250 | "x": 0, 251 | "y": 8 252 | }, 253 | "hiddenSeries": false, 254 | "id": 7, 255 | "legend": { 256 | "alignAsTable": true, 257 | "avg": true, 258 | "current": true, 259 | "hideEmpty": true, 260 | "hideZero": true, 261 | "max": true, 262 | "min": false, 263 | "rightSide": false, 264 | "show": true, 265 | "sort": "current", 266 | "sortDesc": true, 267 | "total": false, 268 | "values": true 269 | }, 270 | "lines": true, 271 | "linewidth": 1, 272 | "links": [], 273 | "nullPointMode": "null", 274 | "options": { 275 | "alertThreshold": true 276 | }, 277 | "percentage": false, 278 | "pluginVersion": "8.1.5", 279 | "pointradius": 5, 280 | "points": false, 281 | "renderer": "flot", 282 | "seriesOverrides": [], 283 | "spaceLength": 10, 284 | "stack": false, 285 | "steppedLine": false, 286 | "targets": [ 287 | { 288 | "exemplar": true, 289 | "expr": "sum(irate(l3afd_BPFMonitorMap{map_name=\"cl_drop_count_map_0_scalar\", ebpf_program=\"connection-limit\"}[2m])) by (host)", 290 | "hide": false, 291 | "interval": "30s", 292 | "legendFormat": "{{host}}", 293 | "refId": "A" 294 | } 295 | ], 296 | "thresholds": [], 297 | "timeFrom": null, 298 | "timeRegions": [], 299 | "timeShift": null, 300 | "title": "dropped connections", 301 | "tooltip": { 302 | "shared": true, 303 | "sort": 2, 304 | "value_type": "individual" 305 | }, 306 | "type": "graph", 307 | "xaxis": { 308 | "buckets": null, 309 | "mode": "time", 310 | "name": null, 311 | "show": true, 312 | "values": [] 313 | }, 314 | "yaxes": [ 315 | { 316 | "format": "short", 317 | "label": "Drop conn / sec", 318 | "logBase": 1, 319 | "max": null, 320 | "min": "0", 321 | "show": true 322 | }, 323 | { 324 | "format": "short", 325 | "label": null, 326 | "logBase": 1, 327 | "max": null, 328 | "min": null, 329 | "show": false 330 | } 331 | ], 332 | "yaxis": { 333 | "align": false, 334 | "alignLevel": null 335 | } 336 | } 337 | ], 338 | "refresh": false, 339 | "schemaVersion": 30, 340 | "style": "dark", 341 | "tags": [], 342 | "templating": { 343 | "list": [] 344 | }, 345 | "time": { 346 | "from": "now-15m", 347 | "to": "now" 348 | }, 349 | "timepicker": { 350 | "refresh_intervals": [ 351 | "5s", 352 | "10s", 353 | "30s", 354 | "1m", 355 | "5m", 356 | "15m", 357 | "30m", 358 | "1h", 359 | "2h", 360 | "1d" 361 | ] 362 | }, 363 | "timezone": "", 364 | "title": "L3af Connection Limiting", 365 | "uid": "lEFJYc2Mk", 366 | "version": 4 367 | } 368 | -------------------------------------------------------------------------------- /dev_environment/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | require 'yaml' 5 | 6 | cfg = YAML.load_file(File.join( 7 | File.dirname(File.expand_path(__FILE__)), 8 | "config.yaml"))['configs'] 9 | 10 | Vagrant.configure("2") do |config| 11 | config.vm.define "l3af" do |l3af| 12 | 13 | # Set boot timeout value 14 | l3af.vm.boot_timeout = 600 15 | 16 | l3af.vm.network "forwarded_port", guest: 8080, host: cfg['host_http_port1'] 17 | l3af.vm.network "forwarded_port", guest: 8081, host: cfg['host_http_port2'] 18 | l3af.vm.network "forwarded_port", guest: 3000, host: cfg['host_grafana_port'] 19 | l3af.vm.network "forwarded_port", guest: 9090, host: cfg['host_prometheus_port'] 20 | l3af.vm.network "forwarded_port", guest: 7080, host: cfg['host_l3af_config_port'] 21 | l3af.vm.network "forwarded_port", guest: 8899, host: cfg['host_l3af_debug_port'] 22 | 23 | l3af.vm.provider "virtualbox" do |vb| 24 | vb.memory = "2048" 25 | end 26 | 27 | l3af.vm.box = "ubuntu/focal64" 28 | if cfg['host_distro_codename'] == "jammy" 29 | config.vm.provision "shell", privileged: false, inline: <<-EOF 30 | echo "Vagrant Box jammy provisioned!" 31 | EOF 32 | l3af.vm.box = "ubuntu/jammy64" 33 | else 34 | # upgrading focal to v5.15 kernel as minimum version requirement for R2 35 | l3af.vm.provision "shell", inline: <<-SHELL 36 | wget https://raw.githubusercontent.com/pimlie/ubuntu-mainline-kernel.sh/master/ubuntu-mainline-kernel.sh 37 | chmod +x ubuntu-mainline-kernel.sh 38 | sudo mv ubuntu-mainline-kernel.sh /usr/local/bin/ 39 | sudo ubuntu-mainline-kernel.sh -i 5.15.0 40 | apt --fix-broken -y install 41 | SHELL 42 | 43 | # restart after upgrade 44 | l3af.vm.provision :reload 45 | end 46 | 47 | if cfg['traffic_mirroring'] == "true" 48 | l3af.vm.network :private_network, ip: "192.168.10.40", :netmask => "255.255.255.0" 49 | end 50 | l3af.vm.hostname = "l3af-local-test.local" 51 | l3af.ssh.forward_agent = true 52 | 53 | l3af.vm.synced_folder cfg['host_l3afd_code_dir'], "/home/vagrant/code/l3afd" 54 | 55 | # Add Grafana apt repo 56 | l3af.vm.provision "shell", inline: <<-SHELL 57 | sudo apt-get install -y apt-transport-https 58 | sudo apt-get install -y software-properties-common wget 59 | wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add - 60 | echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list 61 | sudo apt-get update 62 | SHELL 63 | 64 | # Install package dependencies 65 | l3af.vm.provision "shell", inline: <<-SHELL 66 | export DEBIAN_FRONTEND=noninteractive 67 | export TZ=Etc/UTC 68 | apt-get install -y bc \ 69 | tzdata \ 70 | bison \ 71 | build-essential \ 72 | clang \ 73 | curl \ 74 | exuberant-ctags \ 75 | flex \ 76 | gcc-9 \ 77 | gcc-multilib \ 78 | gnutls-bin \ 79 | grafana \ 80 | jq \ 81 | libc6-dev \ 82 | libcurl4-openssl-dev \ 83 | libelf-dev \ 84 | libjson-c-dev \ 85 | libncurses5-dev \ 86 | libpcap-dev \ 87 | libssl-dev \ 88 | linux-headers-generic \ 89 | linux-tools-common \ 90 | linux-tools-generic \ 91 | llvm \ 92 | net-tools \ 93 | prometheus \ 94 | rsync \ 95 | dwarves \ 96 | zlib1g \ 97 | libelf1 \ 98 | pkg-config \ 99 | libbpf-dev \ 100 | libzstd-dev 101 | SHELL 102 | 103 | # Install Opentelemetry collector 104 | if cfg['otel_collector'] == "true" 105 | l3af.vm.provision "shell", inline: <<-SHELL 106 | OTEL_VERSION="0.97.0" 107 | ARCH=$(uname -p) 108 | case $ARCH in 109 | arm) 110 | echo "Installing OTELC for arm" 111 | OTEL_ARCH=arm64 112 | ;; 113 | aarch64) 114 | echo "Installing OTELC for arm" 115 | OTEL_ARCH=arm64 116 | ;; 117 | x86_64) 118 | echo "Installing OTELC for amd64" 119 | OTEL_ARCH=amd64 120 | ;; 121 | i386) 122 | KERNEL=$(uname -m) 123 | if [ "$KERNEL" = "x86_64" ]; 124 | then 125 | echo "Installing OTELC for amd64" 126 | OTEL_ARCH=amd64 127 | elif [ "$KERNEL" = "i386" ]; 128 | then 129 | echo "Installing OTELC for i386" 130 | OTEL_ARCH=386 131 | else 132 | echo "The CPU kernel $KERNEL is not supported by the script" 133 | exit 1 134 | fi 135 | ;; 136 | *) 137 | echo "The CPU architecture $ARCH is not supported by the script" 138 | exit 1 139 | ;; 140 | esac 141 | OTEL_BINARY="otelcol_${OTEL_VERSION}_linux_${OTEL_ARCH}.tar.gz" 142 | OTEL_DIR="otelcol_${OTEL_VERSION}_linux_${OTEL_ARCH}" 143 | curl --proto '=https' --tlsv1.2 -fOL "https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v${OTEL_VERSION}/${OTEL_BINARY}" 144 | tar -xvf ${OTEL_BINARY} 145 | sudo mv ${OTEL_DIR}/otelcol /usr/local/bin/otelcol 146 | sudo chmod +x /usr/local/bin/otelcol 147 | rm -rf ${OTEL_BINARY} 148 | echo "OTEL Collector version ${OTEL_VERSION} installed successfully." 149 | SHELL 150 | end 151 | 152 | # # Install latest golang version 153 | l3af.vm.provision "shell", inline: <<-SHELL 154 | # Get cpu architecture, arm or amd 155 | ARCH=$(uname -p) 156 | case $ARCH in 157 | arm) 158 | echo "Setting l3af dev environment for arm" 159 | arch=arm64 160 | ;; 161 | aarch64) 162 | echo "Setting l3af dev environment for arm" 163 | arch=arm64 164 | ;; 165 | x86_64) 166 | echo "Setting l3af dev environment for amd64" 167 | arch=amd64 168 | ;; 169 | i386) 170 | KERNEL=$(uname -m) 171 | if [ "$KERNEL" = "x86_64" ]; 172 | then 173 | echo "Setting l3af dev environment for amd64" 174 | arch=amd64 175 | elif [ "$KERNEL" = "i386" ]; 176 | then 177 | echo "Setting l3af dev environment for i386" 178 | arch=386 179 | else 180 | echo "The CPU kernel $KERNEL is not supported by the script" 181 | exit 1 182 | fi 183 | ;; 184 | *) 185 | echo "The CPU architecture $ARCH is not supported by the script" 186 | exit 1 187 | ;; 188 | esac 189 | 190 | os=`uname|tr '[:upper:]' '[:lower:]'` 191 | go_filename=`curl -s https://go.dev/dl/?mode=json|jq '.[0].files[].filename'|grep $os|grep $arch|egrep -v "arm|ppc"|tr -d '"'` 192 | wget https://go.dev/dl/$go_filename 193 | rm -rf /usr/local/go && tar -C /usr/local -xzf $go_filename && rm -f $go_filename 194 | echo export PATH=$PATH:/usr/local/go/bin >> /home/vagrant/.bashrc 195 | echo export PATH=$PATH:/usr/local/go/bin >> /home/vagrant/.profile 196 | echo export PATH=$PATH:/usr/local/go/bin >> /root/.bashrc 197 | SHELL 198 | 199 | # Reboot for updated kernel to load 200 | l3af.vm.provision :reload 201 | 202 | # Copy opentelemetry collector config and start opentelemetry collector 203 | if cfg['otel_collector'] == "true" 204 | l3af.vm.provision "shell", inline: <<-SHELL 205 | mkdir -p "/etc/otelcol/" 206 | cp /vagrant/cfg/otel-collector-config.yml /etc/otelcol/config.yml 207 | /usr/local/bin/otelcol --config=/etc/otelcol/config.yml & 208 | SHELL 209 | end 210 | 211 | l3af.vm.provision :shell, path: "provision.sh" 212 | 213 | # Always start test servers because they aren't managed services 214 | l3af.vm.provision :shell, path: "start_test_servers.sh", run: 'always' 215 | l3af.vm.provision "shell", inline: <<-SHELL 216 | mkdir -p /usr/local/l3afd/latest 217 | mkdir -p /usr/local/l3afd/v2.0.0/l3afd 218 | # for dev purposes I made simlink for v2.0.0 version to your local 219 | ln -s /home/vagrant/go/bin/l3afd /usr/local/l3afd/v2.0.0/l3afd/l3afd 220 | ln -s ./cfg/l3afd.cfg /usr/local/l3afd/v2.0.0/l3afd/l3afd.cfg 221 | ln -s /usr/local/l3afd/v2.0.0/l3afd/l3afd /usr/local/l3afd/latest/l3afd 222 | ln -s /usr/local/l3afd/v2.0.0/l3afd/l3afd.cfg /usr/local/l3afd/latest/l3afd.cfg 223 | SHELL 224 | end 225 | 226 | # Provision the GUE interface for traffic mirroring inside the l3af VM 227 | if cfg['traffic_mirroring'] == "true" 228 | l3af.vm.provision "shell", inline: <<-SHELL 229 | modprobe fou 230 | ip fou add port 6080 gue 231 | ip link add name gue1 type ipip remote 192.168.10.50 local 192.168.10.40 ttl 255 encap gue encap-sport 6080 encap-dport 6080 encap-csum encap-remcsum 232 | ip link set dev gue1 up 233 | SHELL 234 | end 235 | end 236 | 237 | # Provision traffic mirroring collector VM 238 | if cfg['traffic_mirroring'] == "true" 239 | config.vm.define "collector" do |collector| 240 | collector.vm.provider "virtualbox" do |vb| 241 | vb.memory = "512" 242 | end 243 | 244 | collector.vm.network "private_network", ip: "192.168.10.50", :netmask => "255.255.255.0" 245 | collector.vm.box = "ubuntu/focal64" 246 | collector.vm.provision "shell", inline: <<-SHELL 247 | modprobe fou 248 | ip fou add port 6080 gue 249 | ip link add name gue1 type ipip remote 192.168.10.40 local 192.168.10.50 ttl 225 encap gue encap-sport 6080 encap-dport 6080 encap-csum encap-remcsum 250 | ip link set dev gue1 up 251 | SHELL 252 | end 253 | end 254 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/exp_output_3.json: -------------------------------------------------------------------------------- 1 | { 2 | "host_name": "l3af-test-host", 3 | "iface": "ibpfbr", 4 | "ipv4_address": "192.168.15.80", 5 | "bpf_programs": { 6 | "xdp_ingress": [ 7 | { 8 | "id": 0, 9 | "name": "ratelimiting", 10 | "seq_id": 1, 11 | "artifact": "l3af_ratelimiting.tar.gz", 12 | "map_name": "xdp_rl_ingress_next_prog", 13 | "cmd_start": "", 14 | "cmd_stop": "", 15 | "cmd_status": "", 16 | "cmd_config": "", 17 | "cmd_update": "", 18 | "version": "latest", 19 | "user_program_daemon": false, 20 | "is_plugin": false, 21 | "cpu": 0, 22 | "memory": 0, 23 | "admin_status": "enabled", 24 | "prog_type": "xdp", 25 | "rules_file": "", 26 | "rules": "", 27 | "config_file_path": "", 28 | "cfg_version": 1, 29 | "start_args": null, 30 | "stop_args": null, 31 | "status_args": null, 32 | "update_args": null, 33 | "map_args": [ 34 | { 35 | "name": "rl_ports_map", 36 | "args": [ 37 | { 38 | "key": 8080, 39 | "value": 1 40 | }, 41 | { 42 | "key": 8081, 43 | "value": 1 44 | } 45 | ] 46 | }, 47 | { 48 | "name": "rl_config_map", 49 | "args": [ 50 | { 51 | "key": 0, 52 | "value": 2 53 | } 54 | ] 55 | } 56 | ], 57 | "config_args": null, 58 | "monitor_maps": [ 59 | { 60 | "name": "rl_drop_count_map", 61 | "key": 0, 62 | "aggregator": "scalar" 63 | }, 64 | { 65 | "name": "rl_recv_count_map", 66 | "key": 0, 67 | "aggregator": "max-rate" 68 | } 69 | ], 70 | "ebpf_package_repo_url": "", 71 | "object_file": "ratelimiting.bpf.o", 72 | "entry_function_name": "_xdp_ratelimiting" 73 | }, 74 | { 75 | "id": 0, 76 | "name": "connection-limit", 77 | "seq_id": 2, 78 | "artifact": "l3af_connection_limit.tar.gz", 79 | "map_name": "xdp_cl_ingress_next_prog", 80 | "cmd_start": "connection_limit", 81 | "cmd_stop": "", 82 | "cmd_status": "", 83 | "cmd_config": "", 84 | "cmd_update": "", 85 | "version": "latest", 86 | "user_program_daemon": false, 87 | "is_plugin": false, 88 | "cpu": 0, 89 | "memory": 0, 90 | "admin_status": "enabled", 91 | "prog_type": "xdp", 92 | "rules_file": "", 93 | "rules": "", 94 | "config_file_path": "", 95 | "cfg_version": 1, 96 | "start_args": null, 97 | "stop_args": null, 98 | "status_args": null, 99 | "update_args": null, 100 | "map_args": [ 101 | { 102 | "name": "cl_tcp_conns", 103 | "args": [ 104 | { 105 | "key": 8080, 106 | "value": 1 107 | }, 108 | { 109 | "key": 8081, 110 | "value": 1 111 | } 112 | ] 113 | }, 114 | { 115 | "name": "cl_max_conn", 116 | "args": [ 117 | { 118 | "key": 0, 119 | "value": 5 120 | } 121 | ] 122 | } 123 | ], 124 | "config_args": null, 125 | "monitor_maps": [ 126 | { 127 | "name": "cl_recv_count_map", 128 | "key": 0, 129 | "aggregator": "scalar" 130 | }, 131 | { 132 | "name": "cl_drop_count_map", 133 | "key": 0, 134 | "aggregator": "scalar" 135 | }, 136 | { 137 | "name": "cl_conn_count", 138 | "key": 0, 139 | "aggregator": "scalar" 140 | } 141 | ], 142 | "ebpf_package_repo_url": "", 143 | "object_file": "connection_limit.bpf.o", 144 | "entry_function_name": "_xdp_limit_conn" 145 | } 146 | ], 147 | "tc_ingress": [ 148 | { 149 | "id": 0, 150 | "name": "ipfix-flow-exporter", 151 | "seq_id": 1, 152 | "artifact": "l3af_bpf_ipfix.tar.gz", 153 | "map_name": "ipfix_ingress_jmp_table", 154 | "cmd_start": "bpf_ipfix_ingress", 155 | "cmd_stop": "", 156 | "cmd_status": "", 157 | "cmd_config": "", 158 | "cmd_update": "", 159 | "version": "latest", 160 | "user_program_daemon": true, 161 | "is_plugin": false, 162 | "cpu": 0, 163 | "memory": 0, 164 | "admin_status": "enabled", 165 | "prog_type": "tc", 166 | "rules_file": "", 167 | "rules": "", 168 | "config_file_path": "", 169 | "cfg_version": 1, 170 | "start_args": { 171 | "collector_ip": "127.0.0.1", 172 | "collector_port": "49280", 173 | "verbose": "2" 174 | }, 175 | "stop_args": null, 176 | "status_args": null, 177 | "update_args": null, 178 | "map_args": null, 179 | "config_args": null, 180 | "monitor_maps": null, 181 | "ebpf_package_repo_url": "", 182 | "object_file": "bpf_ipfix_ingress.bpf.o", 183 | "entry_function_name": "_ingress_flow_monitoring" 184 | }, 185 | { 186 | "id": 0, 187 | "name": "traffic-mirroring", 188 | "seq_id": 2, 189 | "artifact": "l3af_traffic_mirroring.tar.gz", 190 | "map_name": "mirroring_ingress_jmp_table", 191 | "cmd_start": "mirroring", 192 | "cmd_stop": "", 193 | "cmd_status": "", 194 | "cmd_config": "", 195 | "cmd_update": "", 196 | "version": "latest", 197 | "user_program_daemon": false, 198 | "is_plugin": false, 199 | "cpu": 0, 200 | "memory": 0, 201 | "admin_status": "enabled", 202 | "prog_type": "tc", 203 | "rules_file": "", 204 | "rules": "", 205 | "config_file_path": "", 206 | "cfg_version": 1, 207 | "start_args": { 208 | "dst-port": "8080", 209 | "protocol": "tcp,icmp", 210 | "redirect-to": "lo", 211 | "src-address": "0.0.0.0", 212 | "src-port": "0", 213 | "tunnel-interface-name": "gue1", 214 | "tunnel-local-port": "6080", 215 | "tunnel-remote-address": "127.0.0.1", 216 | "tunnel-remote-port": "6081" 217 | }, 218 | "stop_args": null, 219 | "status_args": null, 220 | "update_args": null, 221 | "map_args": null, 222 | "config_args": null, 223 | "monitor_maps": [], 224 | "ebpf_package_repo_url": "", 225 | "object_file": "mirroring_ingress.bpf.o", 226 | "entry_function_name": "_ingress_redirect" 227 | } 228 | ], 229 | "tc_egress": [ 230 | { 231 | "id": 0, 232 | "name": "ipfix-flow-exporter", 233 | "seq_id": 1, 234 | "artifact": "l3af_bpf_ipfix.tar.gz", 235 | "map_name": "ipfix_egress_jmp_table", 236 | "cmd_start": "bpf_ipfix_egress", 237 | "cmd_stop": "", 238 | "cmd_status": "", 239 | "cmd_config": "", 240 | "cmd_update": "", 241 | "version": "latest", 242 | "user_program_daemon": true, 243 | "is_plugin": false, 244 | "cpu": 0, 245 | "memory": 0, 246 | "admin_status": "enabled", 247 | "prog_type": "tc", 248 | "rules_file": "", 249 | "rules": "", 250 | "config_file_path": "", 251 | "cfg_version": 1, 252 | "start_args": { 253 | "collector_ip": "127.0.0.1", 254 | "collector_port": "49280", 255 | "verbose": "2" 256 | }, 257 | "stop_args": null, 258 | "status_args": null, 259 | "update_args": null, 260 | "map_args": null, 261 | "config_args": null, 262 | "monitor_maps": null, 263 | "ebpf_package_repo_url": "", 264 | "object_file": "bpf_ipfix_egress.bpf.o", 265 | "entry_function_name": "_egress_flow_monitoring" 266 | }, 267 | { 268 | "id": 0, 269 | "name": "traffic-mirroring", 270 | "seq_id": 2, 271 | "artifact": "l3af_traffic_mirroring.tar.gz", 272 | "map_name": "mirroring_egress_jmp_table", 273 | "cmd_start": "mirroring", 274 | "cmd_stop": "", 275 | "cmd_status": "", 276 | "cmd_config": "", 277 | "cmd_update": "", 278 | "version": "latest", 279 | "user_program_daemon": false, 280 | "is_plugin": false, 281 | "cpu": 0, 282 | "memory": 0, 283 | "admin_status": "enabled", 284 | "prog_type": "tc", 285 | "rules_file": "", 286 | "rules": "", 287 | "config_file_path": "", 288 | "cfg_version": 1, 289 | "start_args": { 290 | "dst-address": "0.0.0.0", 291 | "dst-port": "0", 292 | "protocol": "tcp,icmp", 293 | "redirect-to": "lo", 294 | "src-port": "0", 295 | "tunnel-interface-name": "gue1", 296 | "tunnel-local-port": "6080", 297 | "tunnel-remote-address": "127.0.0.1", 298 | "tunnel-remote-port": "6081" 299 | }, 300 | "stop_args": null, 301 | "status_args": null, 302 | "update_args": null, 303 | "map_args": null, 304 | "config_args": null, 305 | "monitor_maps": [], 306 | "ebpf_package_repo_url": "", 307 | "object_file": "mirroring_egress.bpf.o", 308 | "entry_function_name": "_egress_redirect" 309 | } 310 | ], 311 | "probes": null 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /dev_environment/e2e_test/test_suite.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eux 3 | export GOCOVERDIR="/root/coverdata/int" 4 | # this script needs to run as root account, check it 5 | if [[ $EUID -ne 0 ]]; then 6 | echo "This script must be run as root" 7 | exit 1 8 | fi 9 | RED='\033[0;31m' 10 | NC='\033[0m' # No Color 11 | GREEN='\033[0;32m' 12 | 13 | close() { 14 | files=("err" "progids.txt" "tmp" "output.json" "names.txt" "map_names.txt" "l3afd.log") 15 | for d in ${files[@]}; do 16 | if test -f $d; then 17 | rm $d 18 | fi 19 | done 20 | } 21 | 22 | logerr() { 23 | str=$1 24 | close 25 | printf "${RED} error: ${str} ${NC}\n" 26 | exit 1 27 | } 28 | 29 | logsuc() { 30 | str=$1 31 | printf "${GREEN}${str}${NC}\n" 32 | } 33 | 34 | IP=192.168.15.80 35 | # traffic_gen provide traffic for give direction testing 36 | traffic_gen() { 37 | if [ $1 == "ingress" ]; then 38 | ip netns exec bpf bash -c "hey -n 2000 -c 200 http://192.168.15.80:8080" >/dev/null 39 | elif [ $1 == "egress" ]; then 40 | hey -n 2000 -c 200 http://192.168.15.1:8080 >/dev/null 41 | else 42 | echo "Provide valid direction" 43 | exit 1 44 | fi 45 | } 46 | 47 | validate() { 48 | exp_output=$1 49 | api_name=$2 50 | touch progids.txt tmp output.json names.txt err 51 | curl -sS http://${IP}:7080/l3af/configs/v1/ibpfbr >output.json 2>&1 52 | echo >>output.json 53 | if cmp -s output.json /root/l3af-arch/dev_environment/e2e_test/$exp_output; then 54 | curl -sS http://${IP}:8899/bpfs/ibpfbr | jq ".[].ProgID" >progids.txt 2>err 55 | if [ -s err ]; then 56 | cat err 57 | logerr "curl request to debug api failed" 58 | fi 59 | curl -sS http://$IP:8899/bpfs/ibpfbr | jq ".[].Program.name" >names.txt 2>err 60 | if [ -s err ]; then 61 | cat err 62 | logerr "curl request to debug api failed" 63 | fi 64 | curl -sS http://$IP:8899/bpfs/ibpfbr | jq ".[].Program.map_name" >map_names.txt 2>err 65 | if [ -s err ]; then 66 | cat err 67 | log err "curl request to debug api failed" 68 | fi 69 | idarray=() 70 | while IFS= read -r line; do 71 | idarray+=("$line") 72 | done <"progids.txt" 73 | for str in ${idarray[@]}; do 74 | bpftool prog show id $str >tmp 75 | if [ ! -s tmp ]; then 76 | logerr "Program with ProgID ${str} is not running" 77 | fi 78 | cat /dev/null >tmp 79 | done 80 | cl_datapath_verification "ingress" 81 | rl_datapath_verification "ingress" 82 | tm_datapath_verification "ingress" 83 | tm_datapath_verification "egress" 84 | ipfix_datapath_verification "ingress" 85 | ipfix_datapath_verification "egress" 86 | logsuc "$api_name API SUCCESS" 87 | printf "\n" 88 | else 89 | diff /root/l3af-arch/dev_environment/e2e_test/$exp_output output.json 90 | logerr "$api_name API FAILED" 91 | printf "\n" 92 | fi 93 | } 94 | 95 | rl_datapath_verification() { 96 | if grep -q "ratelimiting" names.txt; then 97 | before_rl_drop_count=$(curl -sS $IP:8898/metrics | grep rl_drop_count_map_0_scalar | awk '{print $NF}') 98 | for i in {1..100}; do 99 | traffic_gen $1 100 | after_rl_drop_count=$(curl -sS $IP:8898/metrics | grep rl_drop_count_map_0_scalar | awk '{print $NF}') 101 | if [[ $((after_rl_drop_count - before_rl_drop_count)) -ne 0 ]]; then 102 | logsuc "ratelimiting updated the metrics maps" 103 | return 104 | fi 105 | sleep 1 106 | done 107 | logerr "ratelimiting not updating maps" 108 | fi 109 | } 110 | 111 | cl_datapath_verification() { 112 | if grep -q "connection-limit" names.txt; then 113 | before_cl_recv_count=$(curl -sS $IP:8898/metrics | grep cl_recv_count_map_0_scalar | awk '{print $NF}') 114 | for i in {1..100}; do 115 | traffic_gen $1 116 | after_cl_recv_count=$(curl -sS $IP:8898/metrics | grep cl_recv_count_map_0_scalar | awk '{print $NF}') 117 | if [ $((after_cl_recv_count - before_cl_recv_count)) -ne 0 ]; then 118 | logsuc "connection-limit updated the metrics maps" 119 | return 120 | fi 121 | sleep 1 122 | done 123 | logerr "connection-limit not updating the metrics maps" 124 | fi 125 | } 126 | 127 | ipfix_datapath_verification() { 128 | mapname="ipfix_$1_jmp_table" 129 | if grep -q "ipfix-flow-exporter" names.txt && grep -q $mapname map_names.txt; then 130 | touch first first_err second second_err 131 | tcpdump -i ibpfbr port 8080 -c 2 >first 2>first_err & 132 | tcpdump -i lo port 49280 -c 2 >second 2>second_err & 133 | sleep 4 134 | traffic_gen $1 135 | for i in {1..100}; do 136 | if [[ $(cat first | wc -l) -gt 0 ]] && [[ $(cat second | wc -l) -gt 0 ]]; then 137 | logsuc "ipfix-flow-exporter ($1) collector is receiving packets" 138 | rm first second first_err second_err 139 | return 140 | fi 141 | sleep 1 142 | done 143 | rm first second first_err second_err 144 | logerr "ipfix-flow-exporter ($1) collector not receiving packets" 145 | fi 146 | } 147 | 148 | tm_datapath_verification() { 149 | mapname="mirroring_$1_jmp_table" 150 | if grep -q "traffic-mirroring" names.txt && grep -q $mapname map_names.txt; then 151 | touch tm_first tm_first_err 152 | touch tm_second tm_second_err 153 | tcpdump -i gue1 -c 2 >tm_first 2>tm_first_err & 154 | tcpdump -i lo udp and port 6081 -c 2 >tm_second 2>tm_second_err & 155 | sleep 4 156 | traffic_gen $1 157 | for i in {1..100}; do 158 | if [[ $(cat tm_first | wc -l) -gt 0 ]] && [[ $(cat tm_second | wc -l) -gt 0 ]]; then 159 | logsuc "traffic-mirroring ($1) mirroring the packets" 160 | rm tm_first tm_first_err 161 | rm tm_second tm_second_err 162 | return 163 | fi 164 | sleep 1 165 | done 166 | cat tm_first_err 167 | cat tm_second_err 168 | rm tm_first tm_first_err 169 | rm tm_second tm_second_err 170 | logerr "traffic-mirroring ($1) not mirroring the packets" 171 | fi 172 | } 173 | 174 | api_runner() { 175 | api_name=$1 176 | payload="/root/l3af-arch/dev_environment/e2e_test/$2" 177 | exp_output=$3 178 | curl --max-time 120 -v -X POST http://${IP}:7080/l3af/configs/v1/${api_name} -H "Content-Type: application/json" -d "@${payload}" 179 | if [ $? -ne 0 ]; then 180 | logerr "curl request to the ${api_name} API falied" 181 | return 182 | fi 183 | validate $exp_output $api_name 184 | close 185 | } 186 | 187 | do_graceful_restart() { 188 | payload="/root/l3af-arch/dev_environment/e2e_test/restart.json" 189 | old_pid=$(cat /var/run/l3afd.pid) 190 | curl --max-time 120 -v -X PUT http://${IP}:7080/l3af/configs/v1/restart -H "Content-Type: application/json" -d "@${payload}" 191 | if [ $? -ne 0 ]; then 192 | logerr "curl request to the restart API falied" 193 | return 194 | fi 195 | sleep 5 196 | if [ $(cat /var/run/l3afd.pid) -eq $old_pid ]; then 197 | logerr "curl request to the restart API falied" 198 | return 199 | fi 200 | logsuc "Restart API is successful" 201 | } 202 | sleep 5 203 | echo "with chaining" 204 | api_runner "add" "add_payload.json" "exp_output_1.json" 205 | sleep 2 206 | do_graceful_restart 207 | sleep 5 208 | api_runner "update" "upd_payload.json" "exp_output_2.json" 209 | sleep 2 210 | api_runner "add" "add_tm_payload.json" "exp_output_3.json" 211 | sleep 2 212 | do_graceful_restart 213 | sleep 5 214 | api_runner "delete" "del_ipfix_payload.json" "exp_output_4.json" 215 | sleep 2 216 | api_runner "delete" "del_payload.json" "exp_output_nil.json" 217 | 218 | l3afdID=$(pgrep l3afd) 219 | kill -2 $l3afdID 220 | rm -f /var/l3afd/l3af-config.json 221 | sed -i --follow-symlinks 's/bpf-chaining-enabled: true/bpf-chaining-enabled: false/' $(readlink -f /usr/local/l3afd/latest/l3afd.cfg) 222 | 223 | /usr/local/l3afd/latest/l3afd --config /usr/local/l3afd/latest/l3afd.cfg >l3afd.log 2>&1 & 224 | sleep 5 225 | 226 | echo "without chaining" 227 | api_runner "add" "add_without_chaining_payload.json" "exp_output_5.json" 228 | sleep 2 229 | do_graceful_restart 230 | sleep 5 231 | api_runner "update" "upd_without_chaining_payload.json" "exp_output_6.json" 232 | sleep 2 233 | api_runner "delete" "del_without_chaining_payload.json" "exp_output_nil.json" 234 | sleep 2 235 | api_runner "add" "add_tm_payload.json" "exp_output_7.json" 236 | sleep 2 237 | api_runner "delete" "del_tm_payload.json" "exp_output_nil.json" 238 | 239 | l3afdID=$(pgrep l3afd) 240 | kill -2 $l3afdID 241 | 242 | 243 | # TEST COVERAGE 244 | TESTCOVERAGE_THRESHOLD=50 245 | echo "Quality Gate: checking test coverage is above threshold ..." 246 | echo "Threshold : $TESTCOVERAGE_THRESHOLD %" 247 | 248 | cd /root/l3afd 249 | /usr/local/go/bin/go test -cover ./... -args -test.gocoverdir="/root/coverdata/unit" 250 | /usr/local/go/bin/go tool covdata merge -i=/root/coverdata/int,/root/coverdata/unit -o /root/coverdata/combined 251 | /usr/local/go/bin/go tool covdata textfmt -i=/root/coverdata/combined -o profile.txt 252 | cov=`go tool cover -func=profile.txt | grep total | awk '{print $3}' | tr -d %` 253 | rm -rf profile.txt 254 | totalCoverage=$(echo "($cov+0.5)/1" | bc) 255 | echo "Current test coverage : $totalCoverage %" 256 | 257 | if [[ $totalCoverage -ge $TESTCOVERAGE_THRESHOLD ]]; then 258 | logsuc "OK" 259 | else 260 | logerr "Current test coverage is below threshold. Please add more unit tests or adjust threshold to a lower value." 261 | logerr "Failed" 262 | close 263 | exit 1 264 | 265 | fi 266 | logsuc "TEST COMPLETED" 267 | close 268 | -------------------------------------------------------------------------------- /dev_environment/setup_linux_dev_env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eux 3 | 4 | # This script needs to run as root account, check it 5 | if [[ $EUID -ne 0 ]]; then 6 | echo "This script must be run as root" 7 | exit 1 8 | fi 9 | 10 | # Check for kernel version 5.15 11 | CURRENT_KERNEL_VERSION=$(uname -r | cut -d"." -f1-2) 12 | CURRENT_KERNEL_MAJOR_VERSION=$(echo "${CURRENT_KERNEL_VERSION}" | cut -d"." -f1) 13 | CURRENT_KERNEL_MINOR_VERSION=$(echo "${CURRENT_KERNEL_VERSION}" | cut -d"." -f2) 14 | ALLOWED_KERNEL_VERSION="5.15" 15 | ALLOWED_KERNEL_MAJOR_VERSION=$(echo ${ALLOWED_KERNEL_VERSION} | cut -d"." -f1) 16 | ALLOWED_KERNEL_MINOR_VERSION=$(echo ${ALLOWED_KERNEL_VERSION} | cut -d"." -f2) 17 | if [ "${CURRENT_KERNEL_MAJOR_VERSION}" -lt "${ALLOWED_KERNEL_MAJOR_VERSION}" ]; then 18 | # If the current major version is less than the allowed major version, show an error message and exit. 19 | echo "Error: Kernel ${CURRENT_KERNEL_VERSION} not supported, please update to ${ALLOWED_KERNEL_VERSION}." 20 | exit 21 | fi 22 | if [ "${CURRENT_KERNEL_MAJOR_VERSION}" == "${ALLOWED_KERNEL_MAJOR_VERSION}" ]; then 23 | # If the current major version is equal to the allowed major version, check the minor version. 24 | if [ "${CURRENT_KERNEL_MINOR_VERSION}" -lt "${ALLOWED_KERNEL_MINOR_VERSION}" ]; then 25 | # If the current minor version is less than the allowed minor version, show an error message and exit. 26 | echo "Error: Kernel ${CURRENT_KERNEL_VERSION} not supported, please update to ${ALLOWED_KERNEL_VERSION}." 27 | exit 28 | fi 29 | fi 30 | 31 | # Get cpu architecture, arm or amd 32 | ARCH=$(uname -p) 33 | 34 | case $ARCH in 35 | arm) 36 | echo "Setting l3af dev environment for arm" 37 | arch=arm64 38 | ;; 39 | 40 | aarch64) 41 | echo "Setting l3af dev environment for arm" 42 | arch=arm64 43 | ;; 44 | 45 | x86_64) 46 | echo "Setting l3af dev environment for amd64" 47 | arch=amd64 48 | ;; 49 | 50 | i386) 51 | KERNEL=$(uname -m) 52 | if [ "$KERNEL" = "x86_64" ]; 53 | then 54 | echo "Setting l3af dev environment for amd64" 55 | arch=amd64 56 | elif [ "$KERNEL" = "i386" ]; 57 | then 58 | echo "Setting l3af dev environment for i386" 59 | arch=386 60 | else 61 | echo "The CPU kernel $KERNEL is not supported by the script" 62 | exit 1 63 | fi 64 | ;; 65 | 66 | *) 67 | echo "The CPU architecture $ARCH is not supported by the script" 68 | exit 1 69 | ;; 70 | esac 71 | 72 | cd /root 73 | 74 | 75 | # Install packages 76 | apt-get update 77 | apt-get install -y apt-transport-https software-properties-common wget dpkg 78 | sudo apt-get install -y adduser libfontconfig1 musl 79 | # Get grafana package 80 | if [ "$arch" == amd64 ];then 81 | wget https://dl.grafana.com/oss/release/grafana_10.4.1_amd64.deb 82 | sudo dpkg -i grafana_10.4.1_amd64.deb 83 | rm -rf grafana_10.4.1_amd64.deb 84 | elif [ "$arch" == arm64 ];then 85 | wget https://dl.grafana.com/oss/release/grafana_10.4.1_arm64.deb 86 | sudo dpkg -i grafana_10.4.1_arm64.deb 87 | rm -rf grafana_10.4.1_arm64.deb 88 | else 89 | echo "grafana installation is not available for this cpu architecture" 90 | fi 91 | apt-get clean 92 | apt-get update 93 | 94 | export DEBIAN_FRONTEND=noninteractive 95 | export TZ=Etc/UTC 96 | # Install all necessary packages 97 | # gcc-multilib does not exist for arm64 repos 98 | apt-get install -y bc \ 99 | tzdata \ 100 | bison \ 101 | build-essential \ 102 | clang \ 103 | curl \ 104 | exuberant-ctags \ 105 | flex \ 106 | gcc-9 \ 107 | gnutls-bin \ 108 | jq \ 109 | libc6-dev \ 110 | libcurl4-openssl-dev \ 111 | libelf-dev \ 112 | libjson-c-dev \ 113 | libncurses5-dev \ 114 | libpcap-dev \ 115 | libssl-dev \ 116 | linux-headers-generic \ 117 | linux-tools-common \ 118 | linux-tools-generic \ 119 | linux-tools-$(uname -r) \ 120 | llvm \ 121 | prometheus \ 122 | rsync \ 123 | dwarves \ 124 | zlib1g \ 125 | libelf1 \ 126 | pkg-config \ 127 | libbpf-dev \ 128 | libzstd-dev 129 | 130 | # Install OTEL collector 131 | if [ $# -ge 1 ] && [ "$1" == "--otel-collector" ]; then 132 | OTEL_VERSION="0.97.0" 133 | case $ARCH in 134 | arm) 135 | echo "Installing OTELC for arm" 136 | OTEL_ARCH="arm" 137 | ;; 138 | 139 | aarch64) 140 | echo "Installing OTELC for arm" 141 | OTEL_ARCH="arm64" 142 | ;; 143 | 144 | x86_64) 145 | echo "Installing OTELC for amd64" 146 | OTEL_ARCH="amd64" 147 | ;; 148 | i386) 149 | KERNEL=$(uname -m) 150 | if [ "$KERNEL" = "x86_64" ]; 151 | then 152 | echo "Installing OTELC for amd64" 153 | OTEL_ARCH="amd64" 154 | elif [ "$KERNEL" = "i386" ]; 155 | then 156 | echo "Installing OTELC for i386" 157 | OTEL_ARCH="386" 158 | else 159 | echo "The CPU kernel $KERNEL is not supported by the script" 160 | exit 1 161 | fi 162 | ;; 163 | 164 | *) 165 | echo "The CPU architecture $ARCH is not supported by the script" 166 | exit 1 167 | ;; 168 | esac 169 | OTEL_BINARY="otelcol_${OTEL_VERSION}_linux_${OTEL_ARCH}.tar.gz" 170 | OTEL_DIR="otelcol_${OTEL_VERSION}_linux_${OTEL_ARCH}" 171 | curl --proto '=https' --tlsv1.2 -fOL "https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v${OTEL_VERSION}/${OTEL_BINARY}" 172 | tar -xvf ${OTEL_BINARY} 173 | sudo mv ${OTEL_DIR}/otelcol /usr/local/bin/otelcol 174 | sudo chmod +x /usr/local/bin/otelcol 175 | rm -rf ${OTEL_BINARY} 176 | echo "OTEL Collector version ${OTEL_VERSION} installed successfully." 177 | fi 178 | 179 | 180 | # Install the latest go lang version 181 | os=`uname|tr '[:upper:]' '[:lower:]'` 182 | go_filename=`curl -s https://go.dev/dl/?mode=json|jq '.[0].files[].filename'|grep $os|grep $arch|egrep -v "ppc"|tr -d '"'` 183 | wget https://go.dev/dl/$go_filename 184 | tar -C /usr/local -xzf $go_filename && rm -f $go_filename 185 | export PATH=$PATH:/usr/local/go/bin 186 | echo export PATH=$PATH:/usr/local/go/bin >> /root/.bashrc 187 | go_version=$(go env GOVERSION) 188 | fallback_toolchain="$go_version+auto" 189 | go env -w GOTOOLCHAIN=$fallback_toolchain 190 | 191 | 192 | # Clone the l3afd repo in to root directly 193 | # Can use mapped directory i.e. at /home/ubuntu/Home 194 | if [ ! -d "/root/l3afd" ]; 195 | then 196 | git clone https://github.com/l3af-project/l3afd.git 197 | else 198 | echo "/root/l3afd directory already exists" 199 | fi 200 | 201 | if [ ! -d "/root/l3af-arch" ]; 202 | then 203 | git clone https://github.com/l3af-project/l3af-arch.git 204 | else 205 | echo "/root/l3af-arch directory already exists" 206 | fi 207 | 208 | # Copy grafana configs and dashboards into place 209 | if [ -d "/var/lib/grafana/dashboards" ]; 210 | then 211 | echo "grafana directory already existed" 212 | else 213 | mkdir -p /var/lib/grafana/dashboards 214 | fi 215 | chown grafana:grafana /var/lib/grafana/dashboards 216 | cp /root/l3af-arch/dev_environment/cfg/grafana/dashboards/*.json /var/lib/grafana/dashboards 217 | chown grafana:grafana /var/lib/grafana/dashboards/*.json 218 | cp /root/l3af-arch/dev_environment/cfg/grafana/provisioning/dashboards/l3af.yaml /etc/grafana/provisioning/dashboards 219 | chown root:grafana /etc/grafana/provisioning/dashboards/*.yaml 220 | cp /root/l3af-arch/dev_environment/cfg/grafana/provisioning/datasources/l3af.yaml /etc/grafana/provisioning/datasources 221 | chown root:grafana /etc/grafana/provisioning/datasources/*.yaml 222 | 223 | # Copy prometheus config and restart prometheus 224 | cp /root/l3af-arch/dev_environment/cfg/prometheus.yml /etc/prometheus/prometheus.yml 225 | 226 | # Copy OTEL collector config and start OTEL collector 227 | if [ $# -ge 1 ] && [ "$1" == "--otel-collector" ]; then 228 | echo "Copying OTEL Collector config." 229 | mkdir -p "/etc/otelcol/" 230 | cp /root/l3af-arch/dev_environment/cfg/otel-collector-config.yml /etc/otelcol/config.yml 231 | fi 232 | 233 | 234 | if uname -a | grep -q 'WSL'; 235 | then 236 | echo "WSL DETECTED" 237 | apt-get install daemon 238 | /etc/init.d/prometheus-node-exporter stop 239 | /etc/init.d/prometheus-node-exporter start 240 | 241 | # Start and enable Grafana 242 | sleep 1 243 | /etc/init.d/grafana-server stop || true 244 | /etc/init.d/grafana-server start || true 245 | 246 | # Start OTEL collector 247 | if [ $# -ge 1 ] && [ "$1" == "--otel-collector" ]; then 248 | /usr/local/bin/otelcol --config=/etc/otelcol/config.yml & 249 | else 250 | echo "Skipping OTEL collector binary startup." 251 | fi 252 | else 253 | # The configuration got copied, restart the prometheus service 254 | systemctl daemon-reload 255 | systemctl restart prometheus prometheus-node-exporter 256 | systemctl enable prometheus.service 257 | systemctl enable prometheus-node-exporter.service 258 | 259 | # Start and enable Grafana 260 | systemctl restart grafana-server 261 | systemctl enable grafana-server.service 262 | 263 | # Start OTEL collector 264 | if [ $# -ge 1 ] && [ "$1" == "--otel-collector" ]; then 265 | /usr/local/bin/otelcol --config=/etc/otelcol/config.yml & 266 | else 267 | echo "Skipping OTEL collector binary startup." 268 | fi 269 | fi 270 | 271 | if [ ! -d "/var/log/l3af" ]; 272 | then 273 | mkdir -p /var/log/l3af 274 | fi 275 | if [ ! -d "/var/l3afd" ]; 276 | then 277 | mkdir -p /var/l3afd 278 | fi 279 | 280 | BUILD_DIR=/root 281 | 282 | # Where to store the tar.gz build artifacts 283 | BUILD_ARTIFACT_DIR=/srv/l3afd 284 | if [ ! -d "$BUILD_ARTIFACT_DIR" ]; 285 | then 286 | mkdir -p $BUILD_ARTIFACT_DIR 287 | fi 288 | 289 | cd $BUILD_DIR 290 | 291 | # Get the eBPF-Package-Repository repo containing the eBPF programs 292 | if [ ! -d "$BUILD_DIR/eBPF-Package-Repository" ]; 293 | then 294 | git clone https://github.com/l3af-project/eBPF-Package-Repository.git 295 | fi 296 | cd eBPF-Package-Repository 297 | 298 | if [ "$(which bpftool)" == "" ]; 299 | then 300 | git clone --branch v7.2.0 --recurse-submodules https://github.com/libbpf/bpftool.git 301 | cd bpftool/src 302 | yes | make 303 | cp bpftool /usr/local/bin/ 304 | cd ../../ 305 | rm -rf bpftool 306 | fi 307 | 308 | # Declare an array variable 309 | declare -a progs=("xdp-root" "ratelimiting" "connection-limit" "tc-root" "ipfix-flow-exporter" "traffic-mirroring") 310 | codename=`lsb_release -c -s` 311 | # Now loop through the above array and build the L3AF eBPF programs 312 | for prog in "${progs[@]}" 313 | do 314 | cd $prog 315 | make 316 | PROG_ARTIFACT_DIR=$BUILD_ARTIFACT_DIR/$prog/latest/$codename 317 | mkdir -p $PROG_ARTIFACT_DIR 318 | mv *.tar.gz $PROG_ARTIFACT_DIR 319 | cd ../ 320 | done 321 | 322 | # Compile L3AFD daemon and start the control plane 323 | cd /root/l3afd 324 | make install 325 | 326 | chmod +rx /root/l3af-arch/dev_environment/start_test_servers.sh 327 | mkdir -p /usr/local/l3afd/latest 328 | mkdir -p /usr/local/l3afd/v2.0.0/l3afd 329 | 330 | # for dev purposes I made simlink for v2.0.0 version to your local 331 | ln -s /root/go/bin/l3afd /usr/local/l3afd/v2.0.0/l3afd/l3afd 332 | ln -s /root/l3af-arch/dev_environment/cfg/l3afd.cfg /usr/local/l3afd/v2.0.0/l3afd/l3afd.cfg 333 | 334 | cd /usr/local/l3afd/latest 335 | ln -s /usr/local/l3afd/v2.0.0/l3afd/l3afd l3afd 336 | ln -s /usr/local/l3afd/v2.0.0/l3afd/l3afd.cfg l3afd.cfg 337 | 338 | # Starting test servers and l3afd daemon 339 | if [ $# -ge 1 ] && [ "$1" == "--ci-build" ]; then 340 | # Test coverdata 341 | mkdir -p /root/coverdata 342 | mkdir -p /root/coverdata/int 343 | mkdir -p /root/coverdata/unit 344 | mkdir -p /root/coverdata/combined 345 | export GOCOVERDIR="/root/coverdata/int" 346 | echo export GOCOVERDIR="/root/coverdata/int" >> /root/.bashrc 347 | cd /root/l3afd 348 | make cibuild 349 | /root/l3af-arch/dev_environment/start_test_servers.sh --ci-build 350 | ip netns exec bpf bash /root/l3af-arch/dev_environment/start_test_servers.sh --ci-build 351 | /usr/local/l3afd/latest/l3afd --config /usr/local/l3afd/latest/l3afd.cfg > l3afd.log 2>&1 & 352 | elif [ $# -ge 1 ] && [ "$1" == "--docker" ]; then 353 | echo "Running L3AFD as a docker container" 354 | apt-get install -y docker docker.io 355 | cd /root/l3afd/build-docker 356 | cp /root/go/bin/l3afd . 357 | cp /root/l3afd/config/l3afd.cfg . 358 | /root/l3af-arch/dev_environment/start_test_servers.sh 359 | docker build -t l3afd:latest -f Dockerfile . 360 | docker images 361 | docker run -d -v /srv/l3afd:/srv/l3afd -v /sys/fs/bpf:/sys/fs/bpf -v /sys/kernel/debug/:/sys/kernel/debug/ -v /dev/shm:/dev/shm --privileged --net=host l3afd:latest 362 | docker logs $(docker ps -q) 363 | else 364 | /root/l3af-arch/dev_environment/start_test_servers.sh 365 | /usr/local/l3afd/latest/l3afd --config /usr/local/l3afd/latest/l3afd.cfg & 366 | fi 367 | 368 | -------------------------------------------------------------------------------- /dev_environment/cfg/grafana/dashboards/l3af_ebpf_programs.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": "-- Grafana --", 7 | "enable": true, 8 | "hide": true, 9 | "iconColor": "rgba(0, 211, 255, 1)", 10 | "name": "Annotations & Alerts", 11 | "target": { 12 | "limit": 100, 13 | "matchAny": false, 14 | "tags": [], 15 | "type": "dashboard" 16 | }, 17 | "type": "dashboard" 18 | } 19 | ] 20 | }, 21 | "editable": true, 22 | "gnetId": null, 23 | "graphTooltip": 0, 24 | "id": 3, 25 | "iteration": 1632473918675, 26 | "links": [], 27 | "panels": [ 28 | { 29 | "aliasColors": {}, 30 | "bars": false, 31 | "dashLength": 10, 32 | "dashes": false, 33 | "datasource": null, 34 | "fieldConfig": { 35 | "defaults": { 36 | "links": [] 37 | }, 38 | "overrides": [] 39 | }, 40 | "fill": 1, 41 | "fillGradient": 0, 42 | "gridPos": { 43 | "h": 9, 44 | "w": 12, 45 | "x": 0, 46 | "y": 0 47 | }, 48 | "hiddenSeries": false, 49 | "id": 2, 50 | "legend": { 51 | "avg": false, 52 | "current": false, 53 | "max": false, 54 | "min": false, 55 | "show": true, 56 | "total": false, 57 | "values": false 58 | }, 59 | "lines": true, 60 | "linewidth": 1, 61 | "nullPointMode": "null", 62 | "options": { 63 | "alertThreshold": true 64 | }, 65 | "percentage": false, 66 | "pluginVersion": "8.1.5", 67 | "pointradius": 2, 68 | "points": false, 69 | "renderer": "flot", 70 | "seriesOverrides": [], 71 | "spaceLength": 10, 72 | "stack": false, 73 | "steppedLine": false, 74 | "targets": [ 75 | { 76 | "exemplar": true, 77 | "expr": "l3afd_BPFRunning{ebpf_program=~\".*$BPF.*\"}", 78 | "hide": false, 79 | "interval": "", 80 | "legendFormat": "{{host}}:{{direction}}", 81 | "refId": "A" 82 | } 83 | ], 84 | "thresholds": [], 85 | "timeFrom": null, 86 | "timeRegions": [], 87 | "timeShift": null, 88 | "title": "Running", 89 | "tooltip": { 90 | "shared": true, 91 | "sort": 0, 92 | "value_type": "individual" 93 | }, 94 | "type": "graph", 95 | "xaxis": { 96 | "buckets": null, 97 | "mode": "time", 98 | "name": null, 99 | "show": true, 100 | "values": [] 101 | }, 102 | "yaxes": [ 103 | { 104 | "format": "short", 105 | "label": null, 106 | "logBase": 1, 107 | "max": null, 108 | "min": null, 109 | "show": true 110 | }, 111 | { 112 | "format": "short", 113 | "label": null, 114 | "logBase": 1, 115 | "max": null, 116 | "min": null, 117 | "show": true 118 | } 119 | ], 120 | "yaxis": { 121 | "align": false, 122 | "alignLevel": null 123 | } 124 | }, 125 | { 126 | "aliasColors": {}, 127 | "bars": false, 128 | "dashLength": 10, 129 | "dashes": false, 130 | "datasource": null, 131 | "fieldConfig": { 132 | "defaults": { 133 | "links": [] 134 | }, 135 | "overrides": [] 136 | }, 137 | "fill": 1, 138 | "fillGradient": 0, 139 | "gridPos": { 140 | "h": 9, 141 | "w": 12, 142 | "x": 12, 143 | "y": 0 144 | }, 145 | "hiddenSeries": false, 146 | "id": 4, 147 | "legend": { 148 | "avg": false, 149 | "current": false, 150 | "max": false, 151 | "min": false, 152 | "show": true, 153 | "total": false, 154 | "values": false 155 | }, 156 | "lines": true, 157 | "linewidth": 1, 158 | "nullPointMode": "null", 159 | "options": { 160 | "alertThreshold": true 161 | }, 162 | "percentage": false, 163 | "pluginVersion": "8.1.5", 164 | "pointradius": 2, 165 | "points": false, 166 | "renderer": "flot", 167 | "seriesOverrides": [], 168 | "spaceLength": 10, 169 | "stack": false, 170 | "steppedLine": false, 171 | "targets": [ 172 | { 173 | "exemplar": true, 174 | "expr": "sum(l3afd_BPFRunning{ebpf_program=~\".*$BPF.*\"})by(direction)", 175 | "hide": false, 176 | "interval": "", 177 | "legendFormat": "{{direction}}", 178 | "refId": "A" 179 | } 180 | ], 181 | "thresholds": [], 182 | "timeFrom": null, 183 | "timeRegions": [], 184 | "timeShift": null, 185 | "title": "Running Count", 186 | "tooltip": { 187 | "shared": true, 188 | "sort": 0, 189 | "value_type": "individual" 190 | }, 191 | "type": "graph", 192 | "xaxis": { 193 | "buckets": null, 194 | "mode": "time", 195 | "name": null, 196 | "show": true, 197 | "values": [] 198 | }, 199 | "yaxes": [ 200 | { 201 | "format": "short", 202 | "label": null, 203 | "logBase": 1, 204 | "max": null, 205 | "min": null, 206 | "show": true 207 | }, 208 | { 209 | "format": "short", 210 | "label": null, 211 | "logBase": 1, 212 | "max": null, 213 | "min": null, 214 | "show": true 215 | } 216 | ], 217 | "yaxis": { 218 | "align": false, 219 | "alignLevel": null 220 | } 221 | }, 222 | { 223 | "aliasColors": {}, 224 | "bars": false, 225 | "dashLength": 10, 226 | "dashes": false, 227 | "datasource": null, 228 | "fieldConfig": { 229 | "defaults": { 230 | "links": [] 231 | }, 232 | "overrides": [] 233 | }, 234 | "fill": 1, 235 | "fillGradient": 0, 236 | "gridPos": { 237 | "h": 8, 238 | "w": 12, 239 | "x": 0, 240 | "y": 9 241 | }, 242 | "hiddenSeries": false, 243 | "id": 6, 244 | "legend": { 245 | "alignAsTable": false, 246 | "avg": false, 247 | "current": false, 248 | "max": false, 249 | "min": false, 250 | "show": true, 251 | "total": false, 252 | "values": false 253 | }, 254 | "lines": true, 255 | "linewidth": 1, 256 | "nullPointMode": "null", 257 | "options": { 258 | "alertThreshold": true 259 | }, 260 | "percentage": false, 261 | "pluginVersion": "8.1.5", 262 | "pointradius": 2, 263 | "points": false, 264 | "renderer": "flot", 265 | "seriesOverrides": [], 266 | "spaceLength": 10, 267 | "stack": false, 268 | "steppedLine": false, 269 | "targets": [ 270 | { 271 | "exemplar": true, 272 | "expr": "l3afd_BPFStartCount{ebpf_program=~\".*$BPF.*\"}", 273 | "hide": false, 274 | "interval": "", 275 | "legendFormat": "{{host}}:{{direction}}", 276 | "refId": "A" 277 | } 278 | ], 279 | "thresholds": [], 280 | "timeFrom": null, 281 | "timeRegions": [], 282 | "timeShift": null, 283 | "title": "Start Count", 284 | "tooltip": { 285 | "shared": true, 286 | "sort": 0, 287 | "value_type": "individual" 288 | }, 289 | "type": "graph", 290 | "xaxis": { 291 | "buckets": null, 292 | "mode": "time", 293 | "name": null, 294 | "show": true, 295 | "values": [] 296 | }, 297 | "yaxes": [ 298 | { 299 | "format": "short", 300 | "label": null, 301 | "logBase": 1, 302 | "max": null, 303 | "min": null, 304 | "show": true 305 | }, 306 | { 307 | "format": "short", 308 | "label": null, 309 | "logBase": 1, 310 | "max": null, 311 | "min": null, 312 | "show": true 313 | } 314 | ], 315 | "yaxis": { 316 | "align": false, 317 | "alignLevel": null 318 | } 319 | }, 320 | { 321 | "aliasColors": {}, 322 | "bars": false, 323 | "dashLength": 10, 324 | "dashes": false, 325 | "datasource": null, 326 | "fieldConfig": { 327 | "defaults": { 328 | "links": [] 329 | }, 330 | "overrides": [] 331 | }, 332 | "fill": 1, 333 | "fillGradient": 0, 334 | "gridPos": { 335 | "h": 8, 336 | "w": 12, 337 | "x": 12, 338 | "y": 9 339 | }, 340 | "hiddenSeries": false, 341 | "id": 7, 342 | "legend": { 343 | "avg": false, 344 | "current": false, 345 | "max": false, 346 | "min": false, 347 | "show": true, 348 | "total": false, 349 | "values": false 350 | }, 351 | "lines": true, 352 | "linewidth": 1, 353 | "nullPointMode": "null", 354 | "options": { 355 | "alertThreshold": true 356 | }, 357 | "percentage": false, 358 | "pluginVersion": "8.1.5", 359 | "pointradius": 2, 360 | "points": false, 361 | "renderer": "flot", 362 | "seriesOverrides": [], 363 | "spaceLength": 10, 364 | "stack": false, 365 | "steppedLine": false, 366 | "targets": [ 367 | { 368 | "exemplar": true, 369 | "expr": "l3afd_BPFStopCount{ebpf_program=~\".*$BPF.*\"}", 370 | "hide": false, 371 | "interval": "", 372 | "legendFormat": "{{host}}:{{direction}}", 373 | "refId": "A" 374 | } 375 | ], 376 | "thresholds": [], 377 | "timeFrom": null, 378 | "timeRegions": [], 379 | "timeShift": null, 380 | "title": "Stop Count", 381 | "tooltip": { 382 | "shared": true, 383 | "sort": 0, 384 | "value_type": "individual" 385 | }, 386 | "type": "graph", 387 | "xaxis": { 388 | "buckets": null, 389 | "mode": "time", 390 | "name": null, 391 | "show": true, 392 | "values": [] 393 | }, 394 | "yaxes": [ 395 | { 396 | "format": "short", 397 | "label": null, 398 | "logBase": 1, 399 | "max": null, 400 | "min": null, 401 | "show": true 402 | }, 403 | { 404 | "format": "short", 405 | "label": null, 406 | "logBase": 1, 407 | "max": null, 408 | "min": null, 409 | "show": true 410 | } 411 | ], 412 | "yaxis": { 413 | "align": false, 414 | "alignLevel": null 415 | } 416 | } 417 | ], 418 | "refresh": "10s", 419 | "schemaVersion": 30, 420 | "style": "dark", 421 | "tags": [], 422 | "templating": { 423 | "list": [ 424 | { 425 | "allValue": null, 426 | "current": { 427 | "selected": false, 428 | "text": "ratelimiting", 429 | "value": "ratelimiting" 430 | }, 431 | "description": null, 432 | "error": null, 433 | "hide": 0, 434 | "includeAll": false, 435 | "label": "BPF", 436 | "multi": false, 437 | "name": "BPF", 438 | "options": [ 439 | { 440 | "selected": true, 441 | "text": "ratelimiting", 442 | "value": "ratelimiting" 443 | }, 444 | { 445 | "selected": false, 446 | "text": "connection-limit", 447 | "value": "connection-limit" 448 | }, 449 | { 450 | "selected": false, 451 | "text": "ipfix-flow-exporter", 452 | "value": "ipfix" 453 | }, 454 | { 455 | "selected": false, 456 | "text": "traffic-mirroring", 457 | "value": "traffic-mirroring" 458 | } 459 | ], 460 | "query": "ratelimiting,connection-limit,ipfix,traffic-mirroring", 461 | "queryValue": "", 462 | "skipUrlSync": false, 463 | "type": "custom" 464 | } 465 | ] 466 | }, 467 | "time": { 468 | "from": "now-30m", 469 | "to": "now" 470 | }, 471 | "timepicker": { 472 | "refresh_intervals": [ 473 | "5s", 474 | "10s", 475 | "30s", 476 | "1m", 477 | "5m", 478 | "15m", 479 | "30m", 480 | "1h", 481 | "2h", 482 | "1d" 483 | ] 484 | }, 485 | "timezone": "", 486 | "title": "L3AF eBPF Programs", 487 | "uid": "565yC1KGz", 488 | "version": 7 489 | } 490 | --------------------------------------------------------------------------------