1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
// Copyright 2019 Authors of Red Sift
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
/*!
Cargo subcommand for working with Rust eBPF programs.
# Overview
`cargo-bpf` is part of the [`redbpf`](https://github.com/foniod/redbpf)
project. In addition to `cargo-bpf`, the `redbpf` project includes
[`redbpf-probes`](../../redbpf_probes/) and
[`redbpf-macros`](../../redbpf_macros/), which provide an idiomatic Rust API to
write programs that can be compiled to eBPF bytecode and executed by the linux
in-kernel eBPF virtual machine.
# Installation
To install `cargo bpf` simply run:
```
cargo install cargo-bpf
```
# Creating a new project
After installng `cargo bpf`, you can create a new project with `cargo bpf new`:
```ìgnore
$ cargo bpf new hello-bpf
$ ls -R hello-bpf/
hello-bpf/:
Cargo.toml src
hello-bpf/src:
lib.rs
$ cat hello-bpf/Cargo.toml
[package]
name = "hello-bpf"
version = "0.1.0"
edition = '2018'
[dependencies]
cty = "0.2"
redbpf-macros = "1.0"
redbpf-probes = "1.0"
[features]
default = []
probes = []
[lib]
path = "src/lib.rs"
$ cat hello-bpf/src/lib.rs
#![no_std]
```
As you can see `cargo bpf new` created a new crate `hello-bpf` and
automatically added `redbpf-probes` and `redbpf-macros` as dependencies. It
also created `src/lib.rs` and declared the crate as `no_std`, as eBPF
programs are run in a restricted virtual machine where `std` features are not
available.
# Adding a new eBPF program
Adding a new program is easy:
```
$ cd hello-bpf
$ cargo bpf add block_http
$ tail Cargo.toml
...
[[bin]]
name = "block_http"
path = "src/block_http/main.rs"
required-features = ["probes"]
```
As you can see, running `cargo bpf add` added a new `[bin]` target to the
crate. This new target will contain the eBPF program code.
# Building
Say that you're building an XDP program to block all traffic directed to port 80, and have therefore modified
`src/block_http/main.rs` to include the following code:
```no_run
#![no_std]
#![no_main]
use redbpf_probes::xdp::prelude::*;
program!(0xFFFFFFFE, "GPL");
#[xdp]
pub fn block_port_80(ctx: XdpContext) -> XdpResult {
if let Ok(transport) = ctx.transport() {
if transport.dest() == 80 {
return Ok(XdpAction::Drop);
}
}
Ok(XdpAction::Pass)
}
```
In order to build the program, you can run:
```
$ cargo bpf build block_http
```
`cargo bpf build` will produce eBPF code compatibile with the format expected
by `redbpf::Module` and will place it in
`target/bpf/programs/block_http.elf`.
# Loading a program during development
`cargo bpf` includes a simple `load` subcommand that can be used during
development to test that your eBPF program is loading and producing the
expected output.
Loading eBPF programs requires admin priviledges, so you'll have to run
`load` as root or with sudo:
```
$ sudo cargo bpf load -i eth0 target/bpf/programs/block_http.elf
```
*/
mod build_constants;
#[cfg(feature = "bindings")]
mod accessors;
#[cfg(feature = "bindings")]
pub mod bindgen;
#[cfg(feature = "build")]
mod build;
#[cfg(feature = "build")]
mod llvm;
#[cfg(feature = "command-line")]
mod load;
#[cfg(feature = "command-line")]
mod new;
#[cfg(feature = "command-line")]
mod new_program;
pub struct CommandError(pub String);
impl std::convert::From<std::io::Error> for CommandError {
fn from(e: std::io::Error) -> CommandError {
CommandError(format!("{}", e))
}
}
#[cfg(feature = "build")]
pub use build::*;
#[cfg(feature = "command-line")]
pub use load::load;
#[cfg(feature = "command-line")]
pub use new::new;
#[cfg(feature = "command-line")]
pub use new_program::new_program;