Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,25 @@ jobs:
steps:
- uses: actions/checkout@v6.0.1

- name: Define additional Neutron policies
run: |
mkdir /tmp/neutron-policies
cat << EOF >> /tmp/neutron-policies/port-binding.yaml
---
"create_port:binding:profile": "rule:member or rule:admin or rule:service_api"
"update_port:binding:profile": "rule:member or rule:admin or rule:service_api"
EOF

- name: Deploy devstack
uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1
with:
enable_workaround_docker_io: 'false'
branch: ${{ matrix.openstack_version }}
enabled_services: "openstack-cli-server"
conf_overrides: |
[[post-config|\$NEUTRON_CONF]]
[oslo-policy]
policy_dirs = /tmp/neutron-policies

- name: Deploy a Kind Cluster
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab
Expand Down
31 changes: 31 additions & 0 deletions api/v1alpha1/port_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,23 @@ type FixedIPStatus struct {
SubnetID string `json:"subnetID,omitempty"`
}

type BindingProfile struct {
// trustedVF indicates whether the VF for the port will become
// trusted by physical function to perform some privileged
// operations.
// +optional
TrustedVF *bool `json:"trustedVF,omitempty"`

// capabilities is a list of values that describe capabilities to
// be enabled and used by OVS. In principle, the main usage is for
// enabling OVS hardware offload.
// +kubebuilder:validation:MaxItems:=10
// +kubebuilder:validation:items:MaxLength:=64
// +listType=set
// +optional
Capabilities []string `json:"capabilities,omitempty"`
}

// +kubebuilder:validation:XValidation:rule="has(self.portSecurity) && self.portSecurity == 'Disabled' ? !has(self.securityGroupRefs) : true",message="securityGroupRefs must be empty when portSecurity is set to Disabled"
// +kubebuilder:validation:XValidation:rule="has(self.portSecurity) && self.portSecurity == 'Disabled' ? !has(self.allowedAddressPairs) : true",message="allowedAddressPairs must be empty when portSecurity is set to Disabled"
type PortResourceSpec struct {
Expand Down Expand Up @@ -137,6 +154,13 @@ type PortResourceSpec struct {
// +optional
AdminStateUp *bool `json:"adminStateUp,omitempty"`

// profile is a set of key-value pairs that enable the host to pass
// and receive information to the networking backend about the VIF port.
// We intentionally don't expose it as a map with free-form values
// to enforce Neutron supported values.
// +optional
Profile *BindingProfile `json:"profile,omitempty"`

// securityGroupRefs are the names of the security groups associated
// with this port.
// +kubebuilder:validation:MaxItems:=64
Expand Down Expand Up @@ -258,6 +282,13 @@ type PortResourceStatus struct {
// +optional
VNICType string `json:"vnicType,omitempty"`

// profile is a set of key-value pairs that enable the host to pass
// and receive information to the networking backend about the VIF port.
// We intentionally don't expose it as a map with free-form values
// to enforce Neutron supported values.
// +optional
Profile *BindingProfile `json:"profile,omitempty"`

// portSecurityEnabled indicates whether port security is enabled or not.
// +optional
PortSecurityEnabled *bool `json:"portSecurityEnabled,omitempty"`
Expand Down
35 changes: 35 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 54 additions & 2 deletions cmd/models-schema/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions config/crd/bases/openstack.k-orc.cloud_ports.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,31 @@ spec:
x-kubernetes-validations:
- message: portSecurity cannot be changed to Inherit
rule: '!(oldSelf != ''Inherit'' && self == ''Inherit'')'
profile:
description: |-
profile is a set of key-value pairs that enable the host to pass
and receive information to the networking backend about the VIF port.
We intentionally don't expose it as a map with free-form values
to enforce Neutron supported values.
properties:
capabilities:
description: |-
capabilities is a list of values that describe capabilities to
be enabled and used by OVS. In principle, the main usage is for
enabling OVS hardware offload.
items:
maxLength: 64
type: string
maxItems: 10
type: array
x-kubernetes-list-type: set
trustedVF:
description: |-
trustedVF indicates whether the VF for the port will become
trusted by physical function to perform some privileged
operations.
type: boolean
type: object
projectRef:
description: |-
projectRef is a reference to the ORC Project this resource is associated with.
Expand Down Expand Up @@ -570,6 +595,31 @@ spec:
description: portSecurityEnabled indicates whether port security
is enabled or not.
type: boolean
profile:
description: |-
profile is a set of key-value pairs that enable the host to pass
and receive information to the networking backend about the VIF port.
We intentionally don't expose it as a map with free-form values
to enforce Neutron supported values.
properties:
capabilities:
description: |-
capabilities is a list of values that describe capabilities to
be enabled and used by OVS. In principle, the main usage is for
enabling OVS hardware offload.
items:
maxLength: 64
type: string
maxItems: 10
type: array
x-kubernetes-list-type: set
trustedVF:
description: |-
trustedVF indicates whether the VF for the port will become
trusted by physical function to perform some privileged
operations.
type: boolean
type: object
projectID:
description: projectID is the project owner of the resource.
maxLength: 1024
Expand Down
57 changes: 57 additions & 0 deletions internal/controllers/port/actuator.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ func (actuator portActuator) CreateResource(ctx context.Context, obj *orcv1alpha
VNICType: resource.VNICType,
}

if resource.Profile != nil {
profile := bindingProfileToMap(resource.Profile)
portsBindingOpts.Profile = profile
}

portSecurityOpts := portsecurity.PortCreateOptsExt{
CreateOptsBuilder: portsBindingOpts,
}
Expand Down Expand Up @@ -502,6 +507,45 @@ func handlePortBindingUpdate(updateOpts ports.UpdateOptsBuilder, resource *resou
}
}
}

if resource.Profile != nil {
changed := false

profile := bindingProfileToMap(resource.Profile)
trusted := resource.Profile.TrustedVF
capabilities := resource.Profile.Capabilities
oscCapabilities, _ := osResource.Profile["capabilities"].([]any)

if trusted != nil {
if *trusted != osResource.Profile["trusted"] {
profile["trusted"] = *trusted
changed = true
}
}

if capabilities != nil {
if oscCapabilities == nil || len(capabilities) != len(oscCapabilities) {
profile["capabilities"] = capabilities
changed = true
} else {
for i, e := range capabilities {
if e != oscCapabilities[i].(string) {
profile["capabilities"] = capabilities
changed = true
break
}
}
}
}

if changed {
updateOpts = &portsbinding.UpdateOptsExt{
UpdateOptsBuilder: updateOpts,
Profile: profile,
}
}
}

return updateOpts
}

Expand Down Expand Up @@ -539,6 +583,19 @@ func handleAdminStateUpUpdate(updateOpts *ports.UpdateOpts, resource *resourceSp
}
}

func bindingProfileToMap(bp *orcv1alpha1.BindingProfile) map[string]any {
profile := map[string]any{}
if bp.TrustedVF != nil {
profile["trusted"] = bp.TrustedVF
}

if bp.Capabilities != nil {
profile["capabilities"] = bp.Capabilities
}

return profile
}

type portHelperFactory struct{}

var _ helperFactory = portHelperFactory{}
Expand Down
18 changes: 18 additions & 0 deletions internal/controllers/port/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,23 @@ func (portStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResou
resourceStatus.WithFixedIPs(fixedIPs...)
}

if osResource.Profile != nil {
profileStatus := orcapplyconfigv1alpha1.BindingProfile()
if trusted, ok := osResource.Profile["trusted"]; ok {
profileStatus.WithTrustedVF(trusted.(bool))
}

if capabilities, ok := osResource.Profile["capabilities"]; ok {
capStatus := make([]string, 0, len(capabilities.([]any)))
for _, e := range capabilities.([]any) {
capStatus = append(capStatus, e.(string))
}

profileStatus.WithCapabilities(capStatus...)
}

resourceStatus.WithProfile(profileStatus)
}

statusApply.WithResource(resourceStatus)
}
Loading
Loading