Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow pools dedicated to k8s namespaces in the controller #498

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 50 additions & 3 deletions internal/allocator/allocator.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Allocator struct {
servicesOnIP map[string]map[string]bool // ip.String() -> svc -> allocated?
poolIPsInUse map[string]map[string]int // poolName -> ip.String() -> number of users
poolServices map[string]int // poolName -> #services
nspools map[string][]string // namespace -> poolNames
}

// Port represents one port in use by a service.
Expand Down Expand Up @@ -58,6 +59,7 @@ func New() *Allocator {
servicesOnIP: map[string]map[string]bool{},
poolIPsInUse: map[string]map[string]int{},
poolServices: map[string]int{},
nspools: map[string][]string{},
}
}

Expand All @@ -67,8 +69,18 @@ func (a *Allocator) SetPools(pools map[string]*config.Pool) error {
// can be created. For changing the underlying configuration, the
// only question we have to answer is: can we fit all allocated
// IPs into address pools under the new configuration?

// Handle pools dedicated for namespaces. We need that information
// to check if the new configuration is valid.
nspools := make(map[string][]string)
for n, p := range pools {
if p.Namespace != "" {
nspools[p.Namespace] = append(nspools[p.Namespace], n)
}
}

for svc, alloc := range a.allocated {
if poolFor(pools, alloc.ip) == "" {
if poolForSvc(pools, alloc.ip, svc, nspools) == "" {
return fmt.Errorf("new config not compatible with assigned IPs: service %q cannot own %q under new config", svc, alloc.ip)
}
}
Expand All @@ -82,6 +94,7 @@ func (a *Allocator) SetPools(pools map[string]*config.Pool) error {
}

a.pools = pools
a.nspools = nspools

// Need to rearrange existing pool mappings and counts
for svc, alloc := range a.allocated {
Expand Down Expand Up @@ -127,9 +140,9 @@ func (a *Allocator) assign(svc string, alloc *alloc) {
// Assign assigns the requested ip to svc, if the assignment is
// permissible by sharingKey and backendKey.
func (a *Allocator) Assign(svc string, ip net.IP, ports []Port, sharingKey, backendKey string) error {
pool := poolFor(a.pools, ip)
pool := poolForSvc(a.pools, ip, svc, a.nspools)
if pool == "" {
return fmt.Errorf("%q is not allowed in config", ip)
return fmt.Errorf("%q is not allowed in config for %s", ip, svc)
}
sk := &key{
sharing: sharingKey,
Expand Down Expand Up @@ -367,6 +380,40 @@ func poolFor(pools map[string]*config.Pool, ip net.IP) string {
return ""
}

// poolForSvc returns the pool that owns the requested IP, or "" if none or if there is a namespace mismatch
func poolForSvc(pools map[string]*config.Pool, ip net.IP, svc string, nspools map[string][]string) string {
for pname, p := range pools {
if p.AvoidBuggyIPs && ipConfusesBuggyFirmwares(ip) {
continue
}
for _, cidr := range p.CIDR {
if cidr.Contains(ip) {
if len(nspools) > 0 {
v := strings.Split(svc, "/") // svc format; "namespace/svc-name"
if len(v) < 2 {
return ""
}
serviceNamespace := v[0]
if p.Namespace != "" {
// The pool is dedicated to a namespace.
if p.Namespace != serviceNamespace {
return ""
}
} else {
// The pool is "global".
if _, ok := nspools[serviceNamespace]; ok {
// The service has dedicated pools, it may not take a "global" ip.
return ""
}
}
}
return pname
}
}
}
return ""
}

func portsEqual(a, b []Port) bool {
if len(a) != len(b) {
return false
Expand Down
5 changes: 5 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type selectorRequirements struct {
type addressPool struct {
Protocol Proto
Name string
Namespace string
Addresses []string
AvoidBuggyIPs bool `yaml:"avoid-buggy-ips"`
AutoAssign *bool `yaml:"auto-assign"`
Expand Down Expand Up @@ -129,6 +130,9 @@ type Pool struct {
// If false, prevents IP addresses to be automatically assigned
// from this pool.
AutoAssign bool
// If not empty IP addresses from this pool will only be assigned
// to services with this namespace.
Namespace string
// When an IP is allocated from this pool, how should it be
// translated into BGP announcements?
BGPAdvertisements []*BGPAdvertisement
Expand Down Expand Up @@ -311,6 +315,7 @@ func parseAddressPool(p addressPool, bgpCommunities map[string]uint32) (*Pool, e
Protocol: p.Protocol,
AvoidBuggyIPs: p.AvoidBuggyIPs,
AutoAssign: true,
Namespace: p.Namespace,
}

if p.AutoAssign != nil {
Expand Down