Skip to content

Commit

Permalink
Network: Factor out uplink validation logic (#14846)
Browse files Browse the repository at this point in the history
Pre-requisite for #14631
  • Loading branch information
tomponline authored Jan 24, 2025
2 parents ad3071b + 15ef23c commit 077aaf7
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 51 deletions.
50 changes: 1 addition & 49 deletions lxd/network/driver_ovn.go
Original file line number Diff line number Diff line change
Expand Up @@ -2020,59 +2020,11 @@ func (n *ovn) Create(clientType request.ClientType) error {
return nil
}

// allowedUplinkNetworks returns a list of allowed networks to use as uplinks based on project restrictions.
func (n *ovn) allowedUplinkNetworks(p *api.Project) ([]string, error) {
var uplinkNetworkNames []string

err := n.state.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
// Uplink networks are always from the default project.
networks, err := tx.GetCreatedNetworksByProject(ctx, api.ProjectDefaultName)
if err != nil {
return fmt.Errorf("Failed getting uplink networks: %w", err)
}

// Add any compatible networks to the uplink network list.
for _, network := range networks {
if network.Type == "bridge" || network.Type == "physical" {
uplinkNetworkNames = append(uplinkNetworkNames, network.Name)
}
}

return nil
})
if err != nil {
return nil, err
}

// If project is not restricted, return full network list.
if shared.IsFalseOrEmpty(p.Config["restricted"]) {
return uplinkNetworkNames, nil
}

allowedUplinkNetworkNames := []string{}

// There are no allowed networks if restricted.networks.uplinks is not set.
if p.Config["restricted.networks.uplinks"] == "" {
return allowedUplinkNetworkNames, nil
}

// Parse the allowed uplinks and return any that are present in the actual defined networks.
allowedRestrictedUplinks := shared.SplitNTrimSpace(p.Config["restricted.networks.uplinks"], ",", -1, false)

for _, allowedRestrictedUplink := range allowedRestrictedUplinks {
if shared.ValueInSlice(allowedRestrictedUplink, uplinkNetworkNames) {
allowedUplinkNetworkNames = append(allowedUplinkNetworkNames, allowedRestrictedUplink)
}
}

return allowedUplinkNetworkNames, nil
}

// validateUplinkNetwork checks if uplink network is allowed, and if empty string is supplied then tries to select
// an uplink network from the allowedUplinkNetworks() list if there is only one allowed network.
// Returns chosen uplink network name to use.
func (n *ovn) validateUplinkNetwork(p *api.Project, uplinkNetworkName string) (string, error) {
allowedUplinkNetworks, err := n.allowedUplinkNetworks(p)
allowedUplinkNetworks, err := AllowedUplinkNetworks(n.state, p.Config)
if err != nil {
return "", err
}
Expand Down
48 changes: 48 additions & 0 deletions lxd/network/network_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -1458,3 +1458,51 @@ func ProxyParseAddr(data string) (*deviceConfig.ProxyAddress, error) {

return newProxyAddr, nil
}

// AllowedUplinkNetworks returns a list of allowed networks to use as uplinks based on project restrictions.
func AllowedUplinkNetworks(s *state.State, projectConfig map[string]string) ([]string, error) {
var uplinkNetworkNames []string

// There are no allowed networks if project is restricted and restricted.networks.uplinks is not set.
if shared.IsTrue(projectConfig["restricted"]) && projectConfig["restricted.networks.uplinks"] == "" {
return []string{}, nil
}

err := s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error {
// Uplink networks are always from the default project.
networks, err := tx.GetCreatedNetworksByProject(ctx, api.ProjectDefaultName)
if err != nil {
return fmt.Errorf("Failed getting uplink networks: %w", err)
}

// Add any compatible networks to the uplink network list.
for _, network := range networks {
if network.Type == "bridge" || network.Type == "physical" {
uplinkNetworkNames = append(uplinkNetworkNames, network.Name)
}
}

return nil
})
if err != nil {
return nil, err
}

// If project is not restricted, return full network list.
if shared.IsFalseOrEmpty(projectConfig["restricted"]) {
return uplinkNetworkNames, nil
}

allowedUplinkNetworkNames := []string{}

// Parse the allowed uplinks and return any that are present in the actual defined networks.
allowedRestrictedUplinks := shared.SplitNTrimSpace(projectConfig["restricted.networks.uplinks"], ",", -1, false)

for _, allowedRestrictedUplink := range allowedRestrictedUplinks {
if shared.ValueInSlice(allowedRestrictedUplink, uplinkNetworkNames) {
allowedUplinkNetworkNames = append(allowedUplinkNetworkNames, allowedRestrictedUplink)
}
}

return allowedUplinkNetworkNames, nil
}
5 changes: 3 additions & 2 deletions lxd/project/limits/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,9 +470,10 @@ func checkAggregateLimits(info *projectInfo, aggregateKeys []string) error {

// parseHostIDMapRange parse the supplied list of host ID map ranges into a idmap.IdmapEntry slice.
func parseHostIDMapRange(isUID bool, isGID bool, listValue string) ([]idmap.IdmapEntry, error) {
var idmaps []idmap.IdmapEntry
mapRanges := shared.SplitNTrimSpace(listValue, ",", -1, true)
idmaps := make([]idmap.IdmapEntry, 0, len(mapRanges))

for _, listItem := range shared.SplitNTrimSpace(listValue, ",", -1, true) {
for _, listItem := range mapRanges {
rangeStart, rangeSize, err := validate.ParseUint32Range(listItem)
if err != nil {
return nil, err
Expand Down

0 comments on commit 077aaf7

Please sign in to comment.