Skip to content
Draft
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
2 changes: 2 additions & 0 deletions api/v1alpha7/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ type PortOpts struct {
// The names, uuids, filters or any combination these of the security groups to assign to the instance
SecurityGroupFilters []SecurityGroupFilter `json:"securityGroupFilters,omitempty"`
AllowedAddressPairs []AddressPair `json:"allowedAddressPairs,omitempty"`
// SymmetricAllowedAddressPairs if set to true, also updates the allowed_address_pairs of the VIP port with the IP address of the VM port for bidirectional security
SymmetricAllowedAddressPairs bool `json:"symmetricAllowedAddressPairs,omitempty"`
// Enables and disables trunk at port level. If not provided, openStackMachine.Spec.Trunk is inherited.
Trunk *bool `json:"trunk,omitempty"`

Expand Down
61 changes: 61 additions & 0 deletions pkg/cloud/services/networking/port.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/klog/v2"

infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7"
"sigs.k8s.io/cluster-api-provider-openstack/pkg/record"
Expand Down Expand Up @@ -188,9 +189,69 @@ func (s *Service) GetOrCreatePort(eventObject runtime.Object, clusterName string
}
}

if len(addressPairs) > 0 && portOpts.SymmetricAllowedAddressPairs {
err := s.updateVIPsForSymmetricAllowedAddressPair(err, networkID, port, addressPairs)
if err != nil {
return nil, err
}
}

return port, nil
}

// updateVIPsWithAllowedAddressPair updates the allowed_address_pairs of the VIP port with the IP address of the port
func (s *Service) updateVIPsForSymmetricAllowedAddressPair(err error, networkID string, port *ports.Port, addressPairs []ports.AddressPair) error {
if len(port.FixedIPs) == 0 {
return fmt.Errorf("the port %v is created but it has no IP address", port.ID)
}

allPorts, err := s.client.ListPort(ports.ListOpts{
NetworkID: networkID,
})
if err != nil {
return err
}

// Find matching VIP ports and update
for _, ap := range addressPairs {
for _, vip := range allPorts {
if vip.FixedIPs[0].IPAddress == ap.IPAddress {
err := s.updateVipWithAllowedAddressPairs(vip, port.FixedIPs[0].IPAddress, port.MACAddress)
if err != nil {
return err
}
}
}
}
return nil
}

func (s *Service) updateVipWithAllowedAddressPairs(vip ports.Port, portIPAddress, portMACAddress string) error {
// If IP Address is found, not to update VIP
isfound := false
for _, raw := range vip.AllowedAddressPairs {
if raw.IPAddress == portIPAddress {
isfound = true
break
}
}
if !isfound {
vip.AllowedAddressPairs = append(vip.AllowedAddressPairs, ports.AddressPair{
IPAddress: portIPAddress,
MACAddress: portMACAddress,
})
updateOpts := ports.UpdateOpts{
AllowedAddressPairs: &vip.AllowedAddressPairs,
}
klog.Infof("Updating VIP port %v with allowed_address_pairs: %+v", vip.ID, vip.AllowedAddressPairs)
_, err := s.client.UpdatePort(vip.ID, updateOpts)
if err != nil {
return err
}
}
return nil
}

func (s *Service) getSubnetIDForFixedIP(subnet *infrav1.SubnetFilter, networkID string) (string, error) {
if subnet == nil {
return "", nil
Expand Down
Loading