|
1 | 1 | // SPDX-License-Identifier: Apache-2.0
|
2 | 2 | // Copyright Authors of bpfman
|
3 | 3 |
|
| 4 | +use std::{ |
| 5 | + io::ErrorKind, |
| 6 | + path::{Path, PathBuf}, |
| 7 | + str::FromStr, |
| 8 | +}; |
| 9 | + |
4 | 10 | use bpfman::types::ProgramType;
|
5 |
| -use clap::{Args, Parser, Subcommand}; |
| 11 | +use clap::{ArgGroup, Args, Parser, Subcommand}; |
6 | 12 | use hex::FromHex;
|
7 | 13 |
|
8 | 14 | #[derive(Parser, Debug)]
|
@@ -87,9 +93,8 @@ pub(crate) struct LoadImageArgs {
|
87 | 93 | #[command(flatten)]
|
88 | 94 | pub(crate) pull_args: PullBytecodeArgs,
|
89 | 95 |
|
90 |
| - /// Optional: The name of the function that is the entry point for the BPF program. |
91 |
| - /// If not provided, the program name defined as part of the bytecode image will be used. |
92 |
| - #[clap(short, long, verbatim_doc_comment, default_value = "")] |
| 96 | + /// Required: The name of the function that is the entry point for the eBPF program. |
| 97 | + #[clap(short, long, verbatim_doc_comment)] |
93 | 98 | pub(crate) name: String,
|
94 | 99 |
|
95 | 100 | /// Optional: Global variables to be set when program is loaded.
|
@@ -307,9 +312,269 @@ pub(crate) struct GetArgs {
|
307 | 312 |
|
308 | 313 | #[derive(Subcommand, Debug)]
|
309 | 314 | #[command(disable_version_flag = true)]
|
| 315 | +#[allow(clippy::large_enum_variant)] |
310 | 316 | pub(crate) enum ImageSubCommand {
|
311 | 317 | /// Pull an eBPF bytecode image from a remote registry.
|
312 | 318 | Pull(PullBytecodeArgs),
|
| 319 | + /// Build an eBPF bytecode image from local bytecode objects and push to a registry. |
| 320 | + /// |
| 321 | + /// To use, the --container-file and --tag must be included, as well as a pointer to |
| 322 | + /// at least one bytecode file that can be passed in several ways. Use either: |
| 323 | + /// * --bytecode: for a single bytecode built for the host architecture. |
| 324 | + /// * --cilium-ebpf-project: for a cilium/ebpf project directory which contains |
| 325 | + /// multiple object files for different architectures. |
| 326 | + /// * --bc-386-el .. --bc-s390x-eb: to add one or more architecture specific bytecode files. |
| 327 | + /// |
| 328 | + /// Examples: |
| 329 | + /// bpfman image build -f Containerfile.bytecode -t quay.io/<USER>/go-xdp-counter:test \ |
| 330 | + /// -b ./examples/go-xdp-counter/bpf_x86_bpfel.o |
| 331 | + Build(BuildBytecodeArgs), |
| 332 | + /// Generate the OCI image labels for a given bytecode file. |
| 333 | + /// |
| 334 | + /// To use, the --container-file and --tag must be included, as well as a pointer to |
| 335 | + /// at least one bytecode file that can be passed in several ways. Use either: |
| 336 | + /// * --bytecode: for a single bytecode built for the host architecture. |
| 337 | + /// * --cilium-ebpf-project: for a cilium/ebpf project directory which contains |
| 338 | + /// multiple object files for different architectures. |
| 339 | + /// * --bc-386-el .. --bc-s390x-eb: to add one or more architecture specific bytecode files. |
| 340 | + /// |
| 341 | + /// Examples: |
| 342 | + /// bpfman image generate-build-args --bc-amd64-el ./examples/go-xdp-counter/bpf_x86_bpfel.o |
| 343 | + GenerateBuildArgs(GenerateArgs), |
| 344 | +} |
| 345 | + |
| 346 | +/// GoArch represents the architectures understood by golang when the GOOS=linux. |
| 347 | +/// They are used here since the OCI spec and most container tools also use them. |
| 348 | +/// This structure is also the centralized entry point for specifying ALL multi-arch |
| 349 | +/// eBPF bytecode building. |
| 350 | +#[derive(Debug, Clone)] |
| 351 | +pub(crate) enum GoArch { |
| 352 | + X386, |
| 353 | + Amd64, |
| 354 | + Arm, |
| 355 | + Arm64, |
| 356 | + Loong64, |
| 357 | + Mips, |
| 358 | + Mipsle, |
| 359 | + Mips64, |
| 360 | + Mips64le, |
| 361 | + Ppc64, |
| 362 | + Ppc64le, |
| 363 | + Riscv64, |
| 364 | + S390x, |
| 365 | +} |
| 366 | + |
| 367 | +impl FromStr for GoArch { |
| 368 | + type Err = std::io::Error; |
| 369 | + |
| 370 | + fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 371 | + match s { |
| 372 | + "386" => Ok(GoArch::X386), |
| 373 | + "amd64" => Ok(GoArch::Amd64), |
| 374 | + "arm" => Ok(GoArch::Arm), |
| 375 | + "arm64" => Ok(GoArch::Arm64), |
| 376 | + "loong64" => Ok(GoArch::Loong64), |
| 377 | + "mips" => Ok(GoArch::Mips), |
| 378 | + "mipsle" => Ok(GoArch::Mipsle), |
| 379 | + "mips64" => Ok(GoArch::Mips64), |
| 380 | + "mips64le" => Ok(GoArch::Mips64le), |
| 381 | + "ppc64" => Ok(GoArch::Ppc64), |
| 382 | + "ppc64le" => Ok(GoArch::Ppc64le), |
| 383 | + "riscv64" => Ok(GoArch::Riscv64), |
| 384 | + "s390x" => Ok(GoArch::S390x), |
| 385 | + _ => Err(std::io::Error::new(ErrorKind::InvalidInput, "not a valid bytecode arch, please refer to https://go.dev/doc/install/source#environment for valid GOARCHes when GOOS=linux.")), |
| 386 | + } |
| 387 | + } |
| 388 | +} |
| 389 | + |
| 390 | +impl GoArch { |
| 391 | + /// Converts GoArch to a platform string ($GOOS/$GOARCH) that the container |
| 392 | + /// runtimes understand. |
| 393 | + pub(crate) fn get_platform(&self) -> String { |
| 394 | + match self { |
| 395 | + GoArch::X386 => "linux/386".to_string(), |
| 396 | + GoArch::Amd64 => "linux/amd64".to_string(), |
| 397 | + GoArch::Arm => "linux/arm".to_string(), |
| 398 | + GoArch::Arm64 => "linux/arm64".to_string(), |
| 399 | + GoArch::Loong64 => "linux/loong64".to_string(), |
| 400 | + GoArch::Mips => "linux/mips".to_string(), |
| 401 | + GoArch::Mipsle => "linux/mipsle".to_string(), |
| 402 | + GoArch::Mips64 => "linux/mips64".to_string(), |
| 403 | + GoArch::Mips64le => "linux/mips64le".to_string(), |
| 404 | + GoArch::Ppc64 => "linux/ppc64".to_string(), |
| 405 | + GoArch::Ppc64le => "linux/ppc64le".to_string(), |
| 406 | + GoArch::Riscv64 => "linux/riscv64".to_string(), |
| 407 | + GoArch::S390x => "linux/s390x".to_string(), |
| 408 | + } |
| 409 | + } |
| 410 | + |
| 411 | + /// This must be in sync with the build args described in the |
| 412 | + /// Containerfile.bytecode.multi.arch file. |
| 413 | + pub(crate) fn get_build_arg(&self, bc: &Path) -> String { |
| 414 | + match self { |
| 415 | + GoArch::X386 => format!("BC_386_EL={}", bc.display()), |
| 416 | + GoArch::Amd64 => format!("BC_AMD64_EL={}", bc.display()), |
| 417 | + GoArch::Arm => format!("BC_ARM_EL={}", bc.display()), |
| 418 | + GoArch::Arm64 => format!("BC_ARM64_EL={}", bc.display()), |
| 419 | + GoArch::Loong64 => format!("BC_LOONG64_EL={}", bc.display()), |
| 420 | + GoArch::Mips => format!("BC_MIPS_EB={}", bc.display()), |
| 421 | + GoArch::Mipsle => format!("BC_MIPSLE_EL={}", bc.display()), |
| 422 | + GoArch::Mips64 => format!("BC_MIPS64_EB={}", bc.display()), |
| 423 | + GoArch::Mips64le => format!("BC_MIPS64LE_EL={}", bc.display()), |
| 424 | + GoArch::Ppc64 => format!("BC_PPC64_EB={}", bc.display()), |
| 425 | + GoArch::Ppc64le => format!("BC_PPC64LE_EL={}", bc.display()), |
| 426 | + GoArch::Riscv64 => format!("BC_RISCV64_EL={}", bc.display()), |
| 427 | + GoArch::S390x => format!("BC_S390X_EB={}", bc.display()), |
| 428 | + } |
| 429 | + } |
| 430 | + |
| 431 | + /// Discovers the GoArch based on the cilium/ebpf project file-naming conventions. |
| 432 | + pub(crate) fn from_cilium_ebpf_file_str(s: &str) -> Result<Self, std::io::Error> { |
| 433 | + if s.contains("bpf_x86_bpfel.o") { |
| 434 | + Ok(GoArch::Amd64) |
| 435 | + } else if s.contains("bpf_arm_bpfel.o") { |
| 436 | + Ok(GoArch::Arm) |
| 437 | + } else if s.contains("bpf_arm64_bpfel.o") { |
| 438 | + Ok(GoArch::Arm64) |
| 439 | + } else if s.contains("bpf_loongarch_bpfel.o") { |
| 440 | + Ok(GoArch::Loong64) |
| 441 | + } else if s.contains("bpf_mips_bpfeb.o") { |
| 442 | + Ok(GoArch::Mips) |
| 443 | + } else if s.contains("bpf_powerpc_bpfeb.o") { |
| 444 | + Ok(GoArch::Ppc64) |
| 445 | + } else if s.contains("bpf_powerpc_bpfel.o") { |
| 446 | + Ok(GoArch::Ppc64le) |
| 447 | + } else if s.contains("bpf_riscv_bpfel.o") { |
| 448 | + Ok(GoArch::Riscv64) |
| 449 | + } else if s.contains("bpf_s390_bpfeb.o") { |
| 450 | + Ok(GoArch::S390x) |
| 451 | + } else { |
| 452 | + Err(std::io::Error::new(ErrorKind::InvalidInput, "not a valid cilium/ebpf bytecode filename, please refer to https://github.com/cilium/ebpf/blob/main/cmd/bpf2go/gen/target.go#L14")) |
| 453 | + } |
| 454 | + } |
| 455 | +} |
| 456 | + |
| 457 | +#[derive(Args, Debug)] |
| 458 | +#[command(disable_version_flag = true)] |
| 459 | +pub(crate) struct BuildBytecodeArgs { |
| 460 | + /// Optional: bytecode file to use for building the image assuming host architecture. |
| 461 | + /// Example: -b ./bpf_x86_bpfel.o |
| 462 | + #[clap(flatten)] |
| 463 | + pub(crate) bytecode_file: BytecodeFile, |
| 464 | + |
| 465 | + /// Required: Name and optionally a tag in the name:tag format. |
| 466 | + /// Example: --tag quay.io/bpfman-bytecode/xdp_pass:latest |
| 467 | + #[clap(short, long, verbatim_doc_comment)] |
| 468 | + pub(crate) tag: String, |
| 469 | + |
| 470 | + /// Required: Dockerfile to use for building the image. |
| 471 | + /// Example: --container_file Containerfile.bytecode |
| 472 | + #[clap(short = 'f', long, verbatim_doc_comment)] |
| 473 | + pub(crate) container_file: PathBuf, |
| 474 | + |
| 475 | + /// Optional: Container runtime to use, works with docker or podman, defaults to docker |
| 476 | + /// Example: --runtime podman |
| 477 | + #[clap(short, long, verbatim_doc_comment)] |
| 478 | + pub(crate) runtime: Option<String>, |
| 479 | +} |
| 480 | + |
| 481 | +#[derive(Args, Debug)] |
| 482 | +#[clap(group( |
| 483 | + ArgGroup::new("bytecodefile") |
| 484 | + .multiple(false) |
| 485 | + .conflicts_with("multi-arch") |
| 486 | + .args(&["bytecode", "cilium_ebpf_project"]), |
| 487 | +))] |
| 488 | +#[clap(group( |
| 489 | + ArgGroup::new("multi-arch") |
| 490 | + .multiple(true) |
| 491 | + .args(&["bc_386_el", "bc_amd64_el", "bc_arm_el", "bc_arm64_el", "bc_loong64_el", "bc_mips_eb", "bc_mipsle_el", "bc_mips64_eb", "bc_mips64le_el", "bc_ppc64_eb", "bc_ppc64le_el", "bc_riscv64_el", "bc_s390x_eb"]), |
| 492 | +))] |
| 493 | +#[command(disable_version_flag = true)] |
| 494 | +#[group(required = true)] |
| 495 | +pub(crate) struct BytecodeFile { |
| 496 | + /// Optional: bytecode file to use for building the image assuming host architecture. |
| 497 | + /// Example: -b ./examples/go-xdp-counter/bpf_x86_bpfel.o |
| 498 | + #[clap(short, long, verbatim_doc_comment)] |
| 499 | + pub(crate) bytecode: Option<PathBuf>, |
| 500 | + |
| 501 | + /// Optional: bytecode file to use for building the image assuming amd64 architecture. |
| 502 | + /// Example: --bc-386-el ./examples/go-xdp-counter/bpf_386_bpfel.o |
| 503 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 504 | + pub(crate) bc_386_el: Option<PathBuf>, |
| 505 | + |
| 506 | + /// Optional: bytecode file to use for building the image assuming amd64 architecture. |
| 507 | + /// Example: --bc-amd64-el ./examples/go-xdp-counter/bpf_x86_bpfel.o |
| 508 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 509 | + pub(crate) bc_amd64_el: Option<PathBuf>, |
| 510 | + |
| 511 | + /// Optional: bytecode file to use for building the image assuming arm architecture. |
| 512 | + /// Example: --bc-arm-el ./examples/go-xdp-counter/bpf_arm_bpfel.o |
| 513 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 514 | + pub(crate) bc_arm_el: Option<PathBuf>, |
| 515 | + |
| 516 | + /// Optional: bytecode file to use for building the image assuming arm64 architecture. |
| 517 | + /// Example: --bc-arm64-el ./examples/go-xdp-counter/bpf_arm64_bpfel.o |
| 518 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 519 | + pub(crate) bc_arm64_el: Option<PathBuf>, |
| 520 | + |
| 521 | + /// Optional: bytecode file to use for building the image assuming loong64 architecture. |
| 522 | + /// Example: --bc-loong64-el ./examples/go-xdp-counter/bpf_loong64_bpfel.o |
| 523 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 524 | + pub(crate) bc_loong64_el: Option<PathBuf>, |
| 525 | + |
| 526 | + /// Optional: bytecode file to use for building the image assuming mips architecture. |
| 527 | + /// Example: --bc-mips-eb ./examples/go-xdp-counter/bpf_mips_bpfeb.o |
| 528 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 529 | + pub(crate) bc_mips_eb: Option<PathBuf>, |
| 530 | + |
| 531 | + /// Optional: bytecode file to use for building the image assuming mipsle architecture. |
| 532 | + /// Example: --bc-mipsle-el ./examples/go-xdp-counter/bpf_mipsle_bpfel.o |
| 533 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 534 | + pub(crate) bc_mipsle_el: Option<PathBuf>, |
| 535 | + |
| 536 | + /// Optional: bytecode file to use for building the image assuming mips64 architecture. |
| 537 | + /// Example: --bc-mips64-eb ./examples/go-xdp-counter/bpf_mips64_bpfeb.o |
| 538 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 539 | + pub(crate) bc_mips64_eb: Option<PathBuf>, |
| 540 | + |
| 541 | + /// Optional: bytecode file to use for building the image assuming mips64le architecture. |
| 542 | + /// Example: --bc-mips64le-el ./examples/go-xdp-counter/bpf_mips64le_bpfel.o |
| 543 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 544 | + pub(crate) bc_mips64le_el: Option<PathBuf>, |
| 545 | + |
| 546 | + /// Optional: bytecode file to use for building the image assuming ppc64 architecture. |
| 547 | + /// Example: --bc-ppc64-eb ./examples/go-xdp-counter/bpf_ppc64_bpfeb.o |
| 548 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 549 | + pub(crate) bc_ppc64_eb: Option<PathBuf>, |
| 550 | + |
| 551 | + /// Optional: bytecode file to use for building the image assuming ppc64le architecture. |
| 552 | + /// Example: --bc-ppc64le-el ./examples/go-xdp-counter/bpf_ppc64le_bpfel.o |
| 553 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 554 | + pub(crate) bc_ppc64le_el: Option<PathBuf>, |
| 555 | + |
| 556 | + /// Optional: bytecode file to use for building the image assuming riscv64 architecture. |
| 557 | + /// Example: --bc-riscv64-el ./examples/go-xdp-counter/bpf_riscv64_bpfel.o |
| 558 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 559 | + pub(crate) bc_riscv64_el: Option<PathBuf>, |
| 560 | + |
| 561 | + /// Optional: bytecode file to use for building the image assuming s390x architecture. |
| 562 | + /// Example: --bc-s390x-eb ./examples/go-xdp-counter/bpf_s390x_bpfeb.o |
| 563 | + #[clap(long, verbatim_doc_comment, group = "multi-arch")] |
| 564 | + pub(crate) bc_s390x_eb: Option<PathBuf>, |
| 565 | + |
| 566 | + /// Optional: If specified pull multi-arch bytecode files from a cilium/ebpf formatted project |
| 567 | + /// where the bytecode files all contain a standard bpf_<GOARCH>_<(el/eb)>.o tag. |
| 568 | + /// Example: --cilium-ebpf-project ./examples/go-xdp-counter |
| 569 | + #[clap(short, long, verbatim_doc_comment)] |
| 570 | + pub(crate) cilium_ebpf_project: Option<PathBuf>, |
| 571 | +} |
| 572 | + |
| 573 | +#[derive(Args, Debug)] |
| 574 | +#[command(disable_version_flag = true)] |
| 575 | +pub(crate) struct GenerateArgs { |
| 576 | + #[clap(flatten)] |
| 577 | + pub(crate) bytecode: BytecodeFile, |
313 | 578 | }
|
314 | 579 |
|
315 | 580 | #[derive(Args, Debug)]
|
|
0 commit comments