Skip to content

Initial commit of DPU Service generation code#814

Open
aadvani-nvidia wants to merge 4 commits intoNVIDIA:mainfrom
aadvani-nvidia:dpf-services
Open

Initial commit of DPU Service generation code#814
aadvani-nvidia wants to merge 4 commits intoNVIDIA:mainfrom
aadvani-nvidia:dpf-services

Conversation

@aadvani-nvidia
Copy link
Copy Markdown
Contributor

Description

  • Adds code for creating DPF configuration files for dhcp, doca-hbn and dpu-agent

Type of Change

  • [ x] Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Related Issues (Optional)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • [ x] Manual testing performed
  • No testing required (docs, internal refactor, etc.)

Additional Notes

  • Tested by generating a yaml output and comparing with existing DPF configuration files
  • There is still pending work to setup the chains for the DpuDeployment

@aadvani-nvidia aadvani-nvidia requested a review from a team as a code owner April 4, 2026 02:02
@aadvani-nvidia aadvani-nvidia review requested due to automatic review settings April 4, 2026 02:04
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 4, 2026

🔐 TruffleHog Secret Scan

No secrets or credentials found!

Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉

🔗 View scan details

🕐 Last updated: 2026-04-04 02:05:21 UTC | Commit: ad4aa0e

pub const DOCA_HBN_SERVICE_NETWORK: &str = "mybrhbn";

/// DHCP Service Definitions
pub const DHCP_SERVER_SERVICE_NAME: &str = "carbide-dhcp-server";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these don't go in the DPF SDK crate. pull the carbide configs out into the carbide DPF module with the default v2 services

Signed-off-by: Ashok Advani <aadvani@nvidia.com>
- Added DpuServiceInterface and ServiceChains

Signed-off-by: Ashok Advani <aadvani@nvidia.com>
Copilot AI review requested due to automatic review settings April 7, 2026 22:36
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds initial “DPU Service generation” support to the DPF SDK/API, extending initialization to generate additional CRDs (Service NADs and Service Interfaces) and introducing Carbide-specific v2 service definitions.

Changes:

  • Extend SDK service types to include Service NAD specification and interface template types.
  • Add repositories + SDK initialization logic to create/apply DPUServiceNAD and DPUServiceInterface resources.
  • Update API setup to supply an explicit v2 service set; add YAML-generation helper tests.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
crates/dpf/src/types.rs Adds Service NAD and service-interface-template SDK types.
crates/dpf/src/sdk.rs Builds/applies NAD + service interface templates during initialization; changes deployment service-chain construction.
crates/dpf/src/repository/traits.rs Introduces DpuServiceNADRepository and adds apply() to DpuServiceInterfaceRepository.
crates/dpf/src/repository/kube.rs Implements Kube-backed CRUD/apply for DPUServiceNAD and DPUServiceInterface.
crates/dpf/src/test/sdk_initialization.rs Extends mock repos and adds YAML-generation tests for initialized resources/v2 services.
crates/dpf/src/lib.rs Re-exports new Service NAD SDK types.
crates/dpf/Cargo.toml Adds serde_yaml dependency (currently used by tests).
crates/api/src/setup.rs Populates v2 services list instead of an empty list.
crates/api/src/dpf_services.rs Adds Carbide v2 service definitions and default registry/image constants.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +88 to +94
/// Service Network Attachment Definition (NAD)
#[derive(Debug, Clone)]
pub enum ServiceNADResourceType {
Vf,
Sf,
Veth,
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ServiceNADResourceType is used by reference in sdk::build_service_nad, but the enum is not Copy. Matching on service_nad.resource_type will try to move the value out of &ServiceNAD and won’t compile. Fix by deriving Copy for this enum (and/or matching on &service_nad.resource_type / cloning).

Copilot uses AI. Check for mistakes.
Comment on lines +142 to +151
/// Service Network Attachment Definition (NAD)
#[derive(Debug, Clone)]
pub enum DpuServiceInterfaceTemplateType {
Vlan,
Physical,
Pf,
Vf,
Ovn,
Service,
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DpuServiceInterfaceTemplateType is matched on via iface.iface_type in sdk::apply_service_interface_templates, but the enum is not Copy. This will attempt to move the value out of a borrowed &DpuServiceInterfaceTemplateDefinition and won’t compile. Derive Copy for this enum (and/or match on a reference / clone before matching).

Copilot uses AI. Check for mistakes.
}


/// Service Network Attachment Definition (NAD)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above DpuServiceInterfaceTemplateType says “Service Network Attachment Definition (NAD)”, but the enum represents service interface template types. This is misleading documentation for a public SDK type; please update the doc comment to describe interface templates instead of NADs.

Suggested change
/// Service Network Attachment Definition (NAD)
/// Interface template type for a DPU service.

Copilot uses AI. Check for mistakes.
Comment on lines +779 to +836
let all_switches: Vec<DpuDeploymentServiceChainsSwitches> = vec![
DpuDeploymentServiceChainsSwitches {
ports: vec![
DpuDeploymentServiceChainsSwitchesPorts {
service_interface: Some(
DpuDeploymentServiceChainsSwitchesPortsServiceInterface {
match_labels: BTreeMap::from([(
"interface".to_string(),
"p0".to_string(),
)]),
ipam: None,
},
DpuDeploymentServiceChainsSwitchesPorts {
service: Some(DpuDeploymentServiceChainsSwitchesPortsService {
name: chain.service_name.clone(),
interface: chain.service_interface.clone(),
ipam: None,
}),
service_interface: None,
),
service: Some(
DpuDeploymentServiceChainsSwitchesPortsService {
name: "doca-hbn".to_string(),
interface: "p0_if".to_string(),
ipam: None,
}
)
}
],
service_mtu: None,
},
DpuDeploymentServiceChainsSwitches {
ports: vec![
DpuDeploymentServiceChainsSwitchesPorts {
service_interface: Some(
DpuDeploymentServiceChainsSwitchesPortsServiceInterface {
match_labels: BTreeMap::from([(
"interface".to_string(),
"pf0hpf".to_string(),
)]),
ipam: None,
},
],
service_mtu: None,
})
})
.collect();
),
service: Some(
DpuDeploymentServiceChainsSwitchesPortsService {
name: "doca-hbn".to_string(),
interface: "pf0hpf_if".to_string(),
ipam: None,
}
)
},
DpuDeploymentServiceChainsSwitchesPorts {
service_interface: None,
service: Some(
DpuDeploymentServiceChainsSwitchesPortsService {
name: "carbide-dhcp-server".to_string(),
interface: "d_pf0hpf_if".to_string(),
ipam: None,
}
)
}
],
service_mtu: None,
}
];
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build_deployment() no longer derives service_chains from svc.service_chain_switches and instead hard-codes switches for specific service/interface names (e.g. doca-hbn, carbide-dhcp-server). This breaks callers that supply their own service_chain_switches and can generate incorrect deployments when services are renamed or omitted. Restore the previous behavior of building switches from services[*].service_chain_switches (or gate the hard-coded chain behind an explicit config flag).

Copilot uses AI. Check for mistakes.
Comment on lines 59 to +62
hyper = { features = ["client", "http1"], workspace = true }
http = { workspace = true }
once_cell = { workspace = true }
serde_yaml = { workspace = true }
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

serde_yaml is only used in crates/dpf/src/test/sdk_initialization.rs (tests), but it is added as a normal dependency. This needlessly pulls it into non-test builds of the dpf crate. Move serde_yaml to [dev-dependencies] (or gate it behind a feature used only for these tests).

Copilot uses AI. Check for mistakes.
Comment on lines +319 to +353
#[tokio::test]
async fn test_generate_yaml_for_initialized_resources() {
let mock = InitializationMock::default();

let config = InitDpfResourcesConfig {
bfb_url: "http://example.com/test.bfb".to_string(),
deployment_name: "carbide-deployment".to_string(),
..Default::default()
};

let sdk = crate::sdk::DpfSdkBuilder::new(mock.clone(), TEST_NS, "test-password".to_string())
.initialize(&config)
.await
.unwrap();
drop(sdk);

for entry in mock.bfbs.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.flavors.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.service_templates.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.service_configs.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.nads.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.deployments.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests only print YAML to stdout and contain no assertions, so they won’t catch regressions and may add noisy output to CI. Consider converting them into snapshot/assertion-based tests (e.g. compare against expected YAML/JSON) or marking them #[ignore] if they’re intended as local generation helpers.

Copilot uses AI. Check for mistakes.
Comment on lines +355 to +464
#[tokio::test]
async fn test_generate_yaml_for_v2_services() {
use crate::types::{ServiceInterface, ServiceNAD, ServiceNADResourceType};

let mock = InitializationMock::default();

let doca_helm = "https://helm.ngc.nvidia.com/nvidia/doca";
let carbide_helm = "https://gitlab-master.nvidia.com/aadvani/my-helm-project/-/raw/main/charts-repo";
let doca_image = "nvcr.io/nvidia/doca";
let carbide_image = "https://gitlab-master.nvidia.com/aadvani/my-helm-project";

let services = vec![
crate::services::dts_service(&crate::services::ServiceRegistryConfig::default()),
ServiceDefinition {
helm_values: Some(serde_json::json!({
"image": {
"repository": format!("{}/forge-dhcp-server", carbide_image),
"tag": "v1.9.5-arm64-distroless",
}
})),
interfaces: vec![ServiceInterface {
name: "d_pf0hpf_if".to_string(),
network: "mybrsfc-dhcp".to_string(),
}],
service_nad: Some(ServiceNAD {
name: "mybrsfc-dhcp".to_string(),
bridge: Some("br-sfc".to_string()),
resource_type: ServiceNADResourceType::Sf,
ipam: Some(false),
mtu: Some(1500),
}),
..ServiceDefinition::new("carbide-dhcp-server", carbide_helm, "carbide-dhcp-server", "2.0.9")
},
ServiceDefinition {
helm_values: Some(serde_json::json!({
"image": {
"repository": format!("{}/doca-hbn", doca_image),
"tag": "3.2.1-doca3.2.1",
},
"resources": { "memory": "6Gi", "nvidia.com/bf_sf": 2 },
})),
config_values: Some(serde_json::json!({
"configuration": {
"startupYAMLJ2": concat!(
"- header:\n",
" model: BLUEFIELD\n",
" nvue-api-version: nvue_v1\n",
" rev-id: 1.0\n",
" version: HBN 2.4.0\n",
"- set:\n",
" interface:\n",
" p0_if:\n",
" type: swp\n",
" pf0hpf_if:\n",
" type: swp\n",
)
}
})),
interfaces: vec![
ServiceInterface { name: "p0_if".to_string(), network: "mybrhbn".to_string() },
ServiceInterface { name: "pf0hpf_if".to_string(), network: "mybrhbn".to_string() },
],
..ServiceDefinition::new("doca-hbn", doca_helm, "doca-hbn", "1.0.5")
},
ServiceDefinition {
helm_values: Some(serde_json::json!({
"image": {
"repository": format!("{}/forge-dpu-agent", carbide_image),
"tag": "v0.3-arm64-multistage",
}
})),
..ServiceDefinition::new("carbide-dpu-agent", carbide_helm, "carbide-dpu-agent", "0.4.0")
},
];

let config = InitDpfResourcesConfig {
bfb_url: "http://example.com/test.bfb".to_string(),
deployment_name: "carbide-deployment".to_string(),
services,
..Default::default()
};

let sdk = crate::sdk::DpfSdkBuilder::new(mock.clone(), TEST_NS, "test-password".to_string())
.initialize(&config)
.await
.unwrap();
drop(sdk);

for entry in mock.bfbs.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.flavors.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.service_templates.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.service_configs.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.nads.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.service_interfaces.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
for entry in mock.deployments.iter() {
println!("---\n{}", serde_yaml::to_string(entry.value()).unwrap());
}
}
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test builds a large “v2 services” config and then only prints generated YAML without assertions. If this is meant to validate generated CRDs, add concrete checks (counts, key fields, or snapshots). If it’s only a manual YAML generator, mark it #[ignore] to avoid running in normal test suites.

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +35
pub const DEFAULT_CARBIDE_HELM_REGISTRY: &str = "https://gitlab-master.nvidia.com/aadvani/my-helm-project/-/raw/main/charts-repo";

/// Default DOCA container image registry prefix.
pub const DEFAULT_DOCA_IMAGE_REGISTRY: &str = "nvcr.io/nvidia/doca";

/// Default Carbide container image registry prefix.
pub const DEFAULT_CARBIDE_IMAGE_REGISTRY: &str = "https://gitlab-master.nvidia.com/aadvani/my-helm-project";
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default Carbide helm/image registries are set to a specific internal GitLab project URL. As defaults, this can break deployments outside that environment and makes the API behavior environment-specific. Consider defaulting to the public/official registries (or leaving defaults empty) and relying on configuration to override for internal development.

Suggested change
pub const DEFAULT_CARBIDE_HELM_REGISTRY: &str = "https://gitlab-master.nvidia.com/aadvani/my-helm-project/-/raw/main/charts-repo";
/// Default DOCA container image registry prefix.
pub const DEFAULT_DOCA_IMAGE_REGISTRY: &str = "nvcr.io/nvidia/doca";
/// Default Carbide container image registry prefix.
pub const DEFAULT_CARBIDE_IMAGE_REGISTRY: &str = "https://gitlab-master.nvidia.com/aadvani/my-helm-project";
/// Default Carbide helm registry is intentionally unset and should be provided via configuration.
pub const DEFAULT_CARBIDE_HELM_REGISTRY: &str = "";
/// Default DOCA container image registry prefix.
pub const DEFAULT_DOCA_IMAGE_REGISTRY: &str = "nvcr.io/nvidia/doca";
/// Default Carbide container image registry prefix is intentionally unset and should be provided via configuration.
pub const DEFAULT_CARBIDE_IMAGE_REGISTRY: &str = "";

Copilot uses AI. Check for mistakes.
pub const DEFAULT_DOCA_IMAGE_REGISTRY: &str = "nvcr.io/nvidia/doca";

/// Default Carbide container image registry prefix.
pub const DEFAULT_CARBIDE_IMAGE_REGISTRY: &str = "https://gitlab-master.nvidia.com/aadvani/my-helm-project";
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEFAULT_CARBIDE_IMAGE_REGISTRY includes an https:// scheme, but container image references typically must be in the form registry/namespace without a URL scheme. If this value is used to build the Helm image.repository, it will likely produce invalid image references (e.g. https://.../forge-dpu-agent). Consider storing the registry as gitlab-master.nvidia.com/... (no scheme) and keeping transport/protocol out of the image name.

Suggested change
pub const DEFAULT_CARBIDE_IMAGE_REGISTRY: &str = "https://gitlab-master.nvidia.com/aadvani/my-helm-project";
pub const DEFAULT_CARBIDE_IMAGE_REGISTRY: &str = "gitlab-master.nvidia.com/aadvani/my-helm-project";

Copilot uses AI. Check for mistakes.
Signed-off-by: Ashok Advani <aadvani@nvidia.com>
Signed-off-by: Ashok Advani <aadvani@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants