Skip to content

Commit fcd7daf

Browse files
committed
Add Support for TCX Programs
This PR introduces support for TCX based on the current implementation in the astoycos Aya TCX branch. While minor API changes are anticipated before Aya TCX merges, these are expected to be cosmetic and should not significantly affect bpfman. The PR implements a priority-based API, similar to the existing TC API, with a key difference: TCX does not support "proceed_on" configuration as it's not available in the kernel API. Flow continuation is determined by the return value of the current program. It's important to note that neither the Aya nor the kernel APIs directly support priority. They utilize a relative positioning system, requiring new TCX programs to be placed relative to existing ones. To maintain usability across multiple independent applications, we’ve preserved a TC-like priority API in bpfman, which internally maps to Aya’s relative-ordering API. This PR also adds an integration test and example programs for TCX, which have been successfully tested with Mohammed’s TCX bpfman-operator PR (bpfman/bpfman-operator#102). Additionally, due to TCX's requirement for kernel version 6.6 or higher, GitHub Actions have been updated to use ubuntu-24.04. Signed-off-by: Andre Fredette <[email protected]>
1 parent 539f84e commit fcd7daf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2169
-363
lines changed

.github/workflows/build.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ env:
1717

1818
jobs:
1919
check-license:
20-
runs-on: ubuntu-latest
20+
runs-on: ubuntu-24.04
2121
timeout-minutes: 3
2222

2323
steps:
@@ -284,9 +284,9 @@ jobs:
284284
filename: linux-ppc64le
285285
- arch: s390x
286286
filename: linux-s390x
287-
runs-on: ubuntu-latest
288287

289288
name: Build Go Modules (${{ matrix.arch.arch }})
289+
runs-on: ubuntu-24.04
290290
steps:
291291
- name: Checkout bpfman
292292
uses: actions/checkout@v4
@@ -321,7 +321,7 @@ jobs:
321321
GOARCH=${{ matrix.arch.arch }} make build
322322
323323
basic-integration-tests:
324-
runs-on: ubuntu-latest
324+
runs-on: ubuntu-24.04
325325
needs: [build, build-go]
326326
steps:
327327
- name: Set up environment for running integration tests from manual trigger
@@ -336,6 +336,7 @@ jobs:
336336
echo "KRETPROBE_IMAGE_LOC=quay.io/bpfman-bytecode/kretprobe:${GITHUB_REF_NAME}" >> $GITHUB_ENV
337337
echo "XDP_COUNTER_IMAGE_LOC=quay.io/bpfman-bytecode/go-xdp-counter:${GITHUB_REF_NAME}" >> $GITHUB_ENV
338338
echo "TC_COUNTER_IMAGE_LOC=quay.io/bpfman-bytecode/go-tc-counter:${GITHUB_REF_NAME}" >> $GITHUB_ENV
339+
echo "TCX_COUNTER_IMAGE_LOC=quay.io/bpfman-bytecode/go-tcx-counter:${GITHUB_REF_NAME}" >> $GITHUB_ENV
339340
echo "TRACEPOINT_COUNTER_IMAGE_LOC=quay.io/bpfman-bytecode/go-tracepoint-counter:${GITHUB_REF_NAME}" >> $GITHUB_ENV
340341
echo "FENTRY_IMAGE_LOC=quay.io/bpfman-bytecode/fentry:${GITHUB_REF_NAME}" >> $GITHUB_ENV
341342
echo "FEXIT_IMAGE_LOC=quay.io/bpfman-bytecode/fexit:${GITHUB_REF_NAME}" >> $GITHUB_ENV
@@ -419,7 +420,7 @@ jobs:
419420
run: cargo xtask integration-test
420421

421422
build-docs:
422-
runs-on: ubuntu-latest
423+
runs-on: ubuntu-24.04
423424
steps:
424425
- name: Checkout bpfman
425426
uses: actions/checkout@v4
@@ -437,7 +438,7 @@ jobs:
437438
438439
coverage:
439440
needs: [build, build-go]
440-
runs-on: ubuntu-latest
441+
runs-on: ubuntu-24.04
441442
steps:
442443
- name: Download rust coverage artifacts
443444
uses: actions/download-artifact@v4
@@ -457,7 +458,7 @@ jobs:
457458
if: startsWith(github.ref, 'refs/tags/v')
458459
needs: [build]
459460
environment: crates.io
460-
runs-on: ubuntu-latest
461+
runs-on: ubuntu-24.04
461462
steps:
462463
- name: Checkout bpfman
463464
uses: actions/checkout@v4
@@ -510,7 +511,7 @@ jobs:
510511
coverage,
511512
basic-integration-tests,
512513
]
513-
runs-on: ubuntu-latest
514+
runs-on: ubuntu-24.04
514515
steps:
515516
- name: Build Complete
516517
run: echo "Build Complete"

.github/workflows/docs-build.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on: # yamllint disable-line rule:truthy
88

99
jobs:
1010
build-docs:
11-
runs-on: ubuntu-latest
11+
runs-on: ubuntu-24.04
1212
timeout-minutes: 3
1313
steps:
1414
- uses: actions/checkout@v4

.github/workflows/image-build.yaml

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@ on: # yamllint disable-line rule:truthy
1414
workflow_dispatch:
1515

1616
jobs:
17+
<<<<<<< HEAD
1718
# Build bpfman and store the bpfman CLI binary in artifacts for the
1819
# "build-and-push-bytecode-images" step. It will be used to generate
1920
# build args with the "bpfman image generate-build-args" command.
2021
build-bpfman-for-build-arg-gen:
2122
runs-on: ubuntu-latest
23+
=======
24+
build:
25+
runs-on: ubuntu-24.04
26+
>>>>>>> b3d8a827 (Add Support for TCX Programs)
2227
steps:
2328
- name: Checkout bpfman
2429
uses: actions/checkout@v4
@@ -118,7 +123,7 @@ jobs:
118123
packages: write
119124
id-token: write # needed for signing the images with GitHub OIDC Token
120125

121-
runs-on: ubuntu-latest
126+
runs-on: ubuntu-24.04
122127
strategy:
123128
fail-fast: false
124129
matrix:
@@ -163,6 +168,20 @@ jobs:
163168
type=raw,value=latest,enable={{is_default_branch}}
164169
165170
- registry: quay.io
171+
repository: bpfman-userspace
172+
image: go-tcx-counter
173+
context: .
174+
dockerfile: ./examples/go-tcx-counter/container-deployment/Containerfile.go-tcx-counter
175+
tags: |
176+
type=ref,event=branch
177+
type=ref,event=tag
178+
type=ref,event=pr
179+
type=sha,format=long
180+
# set latest tag for default branch
181+
type=raw,value=latest,enable={{is_default_branch}}
182+
183+
- registry: quay.io
184+
# build_language: go - Not building locally, so don't install go tools
166185
repository: bpfman-userspace
167186
image: go-tracepoint-counter
168187
context: .
@@ -334,7 +353,7 @@ jobs:
334353
packages: write
335354
id-token: write # needed for signing the images with GitHub OIDC Token
336355

337-
runs-on: ubuntu-latest
356+
runs-on: ubuntu-24.04
338357
strategy:
339358
fail-fast: false
340359
matrix:
@@ -371,6 +390,22 @@ jobs:
371390
# set latest tag for default branch
372391
type=raw,value=latest,enable={{is_default_branch}}
373392
393+
- registry: quay.io
394+
build_language: go
395+
bpf_build_wrapper: go
396+
repository: bpfman-bytecode
397+
image: go-tcx-counter
398+
context: .
399+
dockerfile: ./Containerfile.bytecode.multi.arch
400+
bytecode_dir: ./examples/go-tcx-counter
401+
tags: |
402+
type=ref,event=branch
403+
type=ref,event=tag
404+
type=ref,event=pr
405+
type=sha,format=long
406+
# set latest tag for default branch
407+
type=raw,value=latest,enable={{is_default_branch}}
408+
374409
- registry: quay.io
375410
build_language: go
376411
bpf_build_wrapper: go
@@ -499,6 +534,22 @@ jobs:
499534
# set latest tag for default branch
500535
type=raw,value=latest,enable={{is_default_branch}}
501536
537+
- registry: quay.io
538+
build_language: rust
539+
bpf_build_wrapper: rust
540+
repository: bpfman-bytecode
541+
image: tcx_test
542+
context: .
543+
dockerfile: ./Containerfile.bytecode.multi.arch
544+
bytecode_dir: ./tests/integration-test/bpf/.output/tcx_test.bpf
545+
tags: |
546+
type=ref,event=branch
547+
type=ref,event=tag
548+
type=ref,event=pr
549+
type=sha,format=long
550+
# set latest tag for default branch
551+
type=raw,value=latest,enable={{is_default_branch}}
552+
502553
- registry: quay.io
503554
build_language: rust
504555
bpf_build_wrapper: rust

Cargo.lock

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ opentelemetry-otlp = { version = "0.15.0", default-features = false }
6262
opentelemetry-semantic-conventions = { version = "0.14.0" }
6363
opentelemetry_sdk = { version = "0.22.1", default-features = false }
6464
predicates = { version = "3.1.2", default-features = false }
65+
procfs = { version = "0.16.0", default-features = false }
6566
prost = { version = "0.12.6", default-features = false }
6667
prost-types = { version = "0.12.6", default-features = false }
6768
public-api = { version = "0.38.0", default-features = false }

bpfman-api/src/bin/rpc/rpc.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ use bpfman::{
44
add_program, get_program, list_programs, pull_bytecode, remove_program,
55
types::{
66
FentryProgram, FexitProgram, KprobeProgram, ListFilter, Location, Program, ProgramData,
7-
TcProceedOn, TcProgram, TracepointProgram, UprobeProgram, XdpProceedOn, XdpProgram,
7+
TcProceedOn, TcProgram, TcxProgram, TracepointProgram, UprobeProgram, XdpProceedOn,
8+
XdpProgram,
89
},
910
};
1011
use bpfman_api::v1::{
1112
attach_info::Info, bpfman_server::Bpfman, bytecode_location::Location as RpcLocation,
1213
list_response::ListResult, FentryAttachInfo, FexitAttachInfo, GetRequest, GetResponse,
1314
KprobeAttachInfo, ListRequest, ListResponse, LoadRequest, LoadResponse, PullBytecodeRequest,
14-
PullBytecodeResponse, TcAttachInfo, TracepointAttachInfo, UnloadRequest, UnloadResponse,
15-
UprobeAttachInfo, XdpAttachInfo,
15+
PullBytecodeResponse, TcAttachInfo, TcxAttachInfo, TracepointAttachInfo, UnloadRequest,
16+
UnloadResponse, UprobeAttachInfo, XdpAttachInfo,
1617
};
1718
use tonic::{Request, Response, Status};
1819

@@ -91,6 +92,21 @@ impl Bpfman for BpfmanLoader {
9192
.map_err(|e| Status::aborted(format!("failed to create tcprogram: {e}")))?,
9293
)
9394
}
95+
Info::TcxAttachInfo(TcxAttachInfo {
96+
priority,
97+
iface,
98+
position: _,
99+
direction,
100+
}) => {
101+
let direction = direction
102+
.try_into()
103+
.map_err(|_| Status::aborted("direction is not a string"))?;
104+
Program::Tcx(
105+
TcxProgram::new(data, priority, iface, direction).map_err(|e| {
106+
Status::aborted(format!("failed to create tcxprogram: {e}"))
107+
})?,
108+
)
109+
}
94110
Info::TracepointAttachInfo(TracepointAttachInfo { tracepoint }) => Program::Tracepoint(
95111
TracepointProgram::new(data, tracepoint)
96112
.map_err(|e| Status::aborted(format!("failed to create tcprogram: {e}")))?,

bpfman-api/src/bpfman.v1.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// This file is @generated by prost-build.
12
#[allow(clippy::derive_partial_eq_without_eq)]
23
#[derive(Clone, PartialEq, ::prost::Message)]
34
pub struct BytecodeImage {
@@ -117,6 +118,18 @@ pub struct TcAttachInfo {
117118
}
118119
#[allow(clippy::derive_partial_eq_without_eq)]
119120
#[derive(Clone, PartialEq, ::prost::Message)]
121+
pub struct TcxAttachInfo {
122+
#[prost(int32, tag = "1")]
123+
pub priority: i32,
124+
#[prost(string, tag = "2")]
125+
pub iface: ::prost::alloc::string::String,
126+
#[prost(int32, tag = "3")]
127+
pub position: i32,
128+
#[prost(string, tag = "4")]
129+
pub direction: ::prost::alloc::string::String,
130+
}
131+
#[allow(clippy::derive_partial_eq_without_eq)]
132+
#[derive(Clone, PartialEq, ::prost::Message)]
120133
pub struct TracepointAttachInfo {
121134
#[prost(string, tag = "1")]
122135
pub tracepoint: ::prost::alloc::string::String,
@@ -164,7 +177,7 @@ pub struct FexitAttachInfo {
164177
#[allow(clippy::derive_partial_eq_without_eq)]
165178
#[derive(Clone, PartialEq, ::prost::Message)]
166179
pub struct AttachInfo {
167-
#[prost(oneof = "attach_info::Info", tags = "2, 3, 4, 5, 6, 7, 8")]
180+
#[prost(oneof = "attach_info::Info", tags = "2, 3, 4, 5, 6, 7, 8, 9")]
168181
pub info: ::core::option::Option<attach_info::Info>,
169182
}
170183
/// Nested message and enum types in `AttachInfo`.
@@ -186,6 +199,8 @@ pub mod attach_info {
186199
FentryAttachInfo(super::FentryAttachInfo),
187200
#[prost(message, tag = "8")]
188201
FexitAttachInfo(super::FexitAttachInfo),
202+
#[prost(message, tag = "9")]
203+
TcxAttachInfo(super::TcxAttachInfo),
189204
}
190205
}
191206
#[allow(clippy::derive_partial_eq_without_eq)]

bpfman-api/src/lib.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use crate::v1::{
1010
attach_info::Info, bytecode_location::Location as V1Location, AttachInfo,
1111
BytecodeImage as V1BytecodeImage, BytecodeLocation, FentryAttachInfo, FexitAttachInfo,
1212
KernelProgramInfo as V1KernelProgramInfo, KprobeAttachInfo, ProgramInfo,
13-
ProgramInfo as V1ProgramInfo, TcAttachInfo, TracepointAttachInfo, UprobeAttachInfo,
14-
XdpAttachInfo,
13+
ProgramInfo as V1ProgramInfo, TcAttachInfo, TcxAttachInfo, TracepointAttachInfo,
14+
UprobeAttachInfo, XdpAttachInfo,
1515
};
1616

1717
#[path = "bpfman.v1.rs"]
@@ -57,6 +57,12 @@ impl TryFrom<&Program> for ProgramInfo {
5757
direction: p.get_direction()?.to_string(),
5858
proceed_on: p.get_proceed_on()?.as_action_vec(),
5959
})),
60+
Program::Tcx(p) => Some(Info::TcxAttachInfo(TcxAttachInfo {
61+
priority: p.get_priority()?,
62+
iface: p.get_iface()?.to_string(),
63+
position: p.get_current_position()?.unwrap_or(0) as i32,
64+
direction: p.get_direction()?.to_string(),
65+
})),
6066
Program::Tracepoint(p) => Some(Info::TracepointAttachInfo(TracepointAttachInfo {
6167
tracepoint: p.get_tracepoint()?.to_string(),
6268
})),

bpfman/src/bin/cli/args.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,26 @@ pub(crate) enum LoadCommands {
185185
proceed_on: Vec<String>,
186186
},
187187
#[command(disable_version_flag = true)]
188+
/// Install an eBPF program on the TCX hook point for a given interface and
189+
/// direction.
190+
Tcx {
191+
/// Required: Direction to apply program.
192+
///
193+
/// [possible values: ingress, egress]
194+
#[clap(short, long, verbatim_doc_comment)]
195+
direction: String,
196+
197+
/// Required: Interface to load program on.
198+
#[clap(short, long)]
199+
iface: String,
200+
201+
/// Optional: Priority to run program in chain. Lower value runs first.
202+
/// [possible values: 1-1000]
203+
/// [default: 1000]
204+
#[clap(short, long)]
205+
priority: i32,
206+
},
207+
#[command(disable_version_flag = true)]
188208
/// Install an eBPF program on a Tracepoint.
189209
Tracepoint {
190210
/// Required: The tracepoint to attach to.

bpfman/src/bin/cli/load.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use bpfman::{
88
add_program,
99
types::{
1010
FentryProgram, FexitProgram, KprobeProgram, Location, Program, ProgramData, TcProceedOn,
11-
TcProgram, TracepointProgram, UprobeProgram, XdpProceedOn, XdpProgram,
11+
TcProgram, TcxProgram, TracepointProgram, UprobeProgram, XdpProceedOn, XdpProgram,
1212
},
1313
};
1414

@@ -113,6 +113,22 @@ impl LoadCommands {
113113
direction.to_string().try_into()?,
114114
)?))
115115
}
116+
LoadCommands::Tcx {
117+
direction,
118+
iface,
119+
priority,
120+
} => {
121+
match direction.as_str() {
122+
"ingress" | "egress" => (),
123+
other => bail!("{} is not a valid direction", other),
124+
};
125+
Ok(Program::Tcx(TcxProgram::new(
126+
data,
127+
*priority,
128+
iface.to_string(),
129+
direction.to_string().try_into()?,
130+
)?))
131+
}
116132
LoadCommands::Tracepoint { tracepoint } => Ok(Program::Tracepoint(
117133
TracepointProgram::new(data, tracepoint.to_string())?,
118134
)),

0 commit comments

Comments
 (0)