Skip to content

Conversation

@frobware
Copy link
Contributor

Summary

This is follow-on work from PR #485 which addressed issue #484 (allowing priority: 0 for BPF programs). PR #485 correctly changed the spec Priority field from int32 to *int32, but also changed the status field to a pointer type. This PR explores and implements using a non-pointer type for the status field instead.

Problem with pointer type in status

The status Priority field was annotated +required but declared as *int32 with json:"priority,omitempty" - these are contradictory: a required field should not be a pointer with omitempty, as that allows it to be absent from the serialised output.

Since the controller always resolves a concrete priority value (either the user's explicit value or the default 1000), the status field should be int32. The status represents what was actually applied to the system, and that is never "unset".

Changes

  1. Revert status types to int32: Change AttachInfoState Priority fields back to int32 for all program types (XDP, TC, TCX and their cluster variants)
  2. Update reconcilers: Use GetPriority() only for spec fields, use direct int32 values for status
  3. Remove unused helper: Remove GetPriorityPointer() which is no longer needed
  4. Update tests: Fix unit and integration tests for the new status type
  5. Define public constant: Add DefaultAttachPriority as a public API constant for the default value (1000)

Design

Field Location Type Behaviour
Spec (AttachInfo) *int32 Optional - nil means "use default", 0 means "explicit zero"
Status (AttachInfoState) int32 Required - always set by controller to actual applied value

Cluster Testing

Test 1: Explicit priority: 0

Created a ClusterBpfApplication with priority: 0:

apiVersion: bpfman.io/v1alpha1
kind: ClusterBpfApplication
metadata:
  name: priority-zero-test
spec:
  nodeSelector: {}
  byteCode:
    image:
      url: quay.io/bpfman-bytecode/go-xdp-counter:latest
  programs:
    - name: xdp_stats
      type: XDP
      xdp:
        links:
          - interfaceSelector:
              primaryNodeInterface: true
            priority: 0

Result - Spec preserved priority: 0:

spec:
  programs:
  - xdp:
      links:
      - priority: 0

Result - Status shows priority: 0:

status:
  programs:
  - xdp:
      links:
      - priority: 0
        linkStatus: Attached

Result - bpfman confirms Priority: 0:

 BPF Function:       xdp_stats
 Priority:           0
 Position:           0

Test 2: Default priority (not specified)

Created a ClusterBpfApplication without specifying priority:

apiVersion: bpfman.io/v1alpha1
kind: ClusterBpfApplication
metadata:
  name: priority-default-test
spec:
  programs:
    - name: xdp_stats
      type: XDP
      xdp:
        links:
          - interfaceSelector:
              interfaces:
                - eth1

Result - Status shows priority: 1000 (default applied by controller):

status:
  programs:
  - xdp:
      links:
      - priority: 1000

Schema verification

$ kubectl explain clusterbpfapplicationstate.status.programs --recursive | grep priority
      priority	<integer> -required-

The status field is now correctly marked as required.

@mergify
Copy link
Contributor

mergify bot commented Jan 12, 2026

@frobware, this pull request is now in conflict and requires a rebase.

@mergify mergify bot added the needs-rebase label Jan 12, 2026
andreaskaris and others added 11 commits January 12, 2026 12:51
Convert the Priority field from int32 to *int32 across all BPF program
types (TC, TCX, XDP) and their cluster variants. This change:

- Removes the default value of 1000 from kubebuilder annotations
- Makes the Priority field truly optional in the API
- Updates all AttachInfo and AttachInfoState structs
- Adds a GetPriority helper function to handle nil pointer cases
- Updates all reconcilers to use the helper function
- Regenerates CRDs and deepcopy code
- Updates tests to use ptr.To() for priority values

This allows users to omit the priority field when they want to use
bpfman's default behavior, rather than always setting an explicit
value. It also follows API best practices to set the default value via
the controller, and not via the CRD definition.

Signed-off-by: Andreas Karis <ak.karis@gmail.com>
Convert cluster and namespace BPF application tests to table-driven
structure for better maintainability and test coverage. Extract common
test functionality into reusable helper functions:
- createFakeClusterReconciler() and createFakeNamespaceReconciler() for
  setup
- runClusterReconciler() and runNamespaceReconciler() for execution
- verifyClusterBpfApplicationState() and
  verifyNamespaceBpfApplicationState()
- verifyClusterBpfProgramState() and verifyNamespaceBpfProgramState()

Inline program definitions within test cases, simplify reconciler setup
in GetBpfAppState tests, and add comprehensive verification of program
status across multiple reconciliation cycles.

Signed-off-by: Andreas Karis <ak.karis@gmail.com>
Extract the NetnsCache map and getNetnsId method from ReconcilerCommon
into a new NetNsCache interface with ReconcilerNetNsCache implementation.
This enables proper unit testing by allowing tests to inject a
MockNetNsCache instead of relying on actual filesystem operations.

Changes:
- Define NetNsCache interface with GetNetNsId and Reset methods
- Implement ReconcilerNetNsCache with the original caching logic
- Update all reconcilers to use NetNsCache.GetNetNsId() instead of
  ReconcilerCommon.getNetnsId()
- Add MockNetNsCache for testing with predefined namespace mappings
- Initialize NetNsCache in main.go and test setup

Signed-off-by: Andreas Karis <ak.karis@gmail.com>
Add unit tests for XDP, TC, and TCX programs to verify that:
- nil priority defaults to 1000
- explicit priority values are correctly set
- zero priority is allowed

The tests cover both cluster-scoped and namespace-scoped BPF
applications, ensuring the priority field is properly handled
and reflected in the program status.

Signed-off-by: Andreas Karis <ak.karis@gmail.com>
Add integration tests to verify BPF program links are correctly ordered
by priority across XDP, TC, and TCX program types.

The new verification framework validates link ordering on each cluster
node by comparing ClusterBpfApplicationState data against actual bpfman
daemon state.

Signed-off-by: Andreas Karis <ak.karis@gmail.com>
The PR bpfman#485 changed Priority from int32 to *int32 in both spec
(AttachInfo) and status (AttachInfoState) types. However, the status
field should remain int32 because the controller always resolves a
concrete priority value after reconciliation.

The field is annotated +required but was declared as *int32 with
json:"priority,omitempty" - these are contradictory: a required field
should not be a pointer with omitempty, as that allows it to be absent
from the serialised output.

This commit reverts only the status types back to int32 whilst keeping
the spec types as *int32 (which correctly allows distinguishing between
"not set" and "explicitly set to 0").

Signed-off-by: Andrew McDermott <amcdermo@redhat.com>
With the AttachInfoState Priority field reverted to int32, update the
reconcilers to:

- Use the Priority value directly when populating status (no longer
  need GetPriorityPointer)
- Compare Priority values directly in findLink functions (no longer
  need GetPriority wrapper for int32 comparisons)
- Use GetPriority only when reading from spec (which remains *int32)

Signed-off-by: Andrew McDermott <amcdermo@redhat.com>
With the status Priority field now int32, the GetPriorityPointer helper
is no longer needed. Remove it along with its unused ptr import.

Signed-off-by: Andrew McDermott <amcdermo@redhat.com>
Remove require.NotNil checks and pointer dereferences for status
Priority fields which are now int32. The GetPriority helper is still
needed when comparing against spec types which remain *int32.

Signed-off-by: Andrew McDermott <amcdermo@redhat.com>
Move the default attach priority value to the API package as a public
constant, providing a single authoritative definition. The helper
function now references this constant rather than a private value.

This ensures the default is defined alongside the types that use it and
can be referenced by documentation and external consumers.

Signed-off-by: Andrew McDermott <amcdermo@redhat.com>
Update the bundle CRD manifests to reflect the status Priority field
being required (int32) rather than optional (*int32).

Signed-off-by: Andrew McDermott <amcdermo@redhat.com>
@frobware
Copy link
Contributor Author

/hold

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.

2 participants