<commit_before>// Copyright Microsoft Corp.
// All rights reserved.

package ipam

import (
	"fmt"
	"net"
	"strings"
)

const (
	// Default address space IDs.
	localDefaultAddressSpaceId  = "LocalDefaultAddressSpace"
	globalDefaultAddressSpaceId = "GlobalDefaultAddressSpace"

	// Address space scopes.
	localScope  = "local"
	globalScope = "global"
)

// Represents the key to an address pool.
type addressPoolId struct {
	asId        string
	subnet      string
	childSubnet string
}

// Represents a set of non-overlapping address pools.
type addressSpace struct {
	Id    string
	Scope string
	Pools map[string]*addressPool
	epoch int
}

// Represents a subnet and the set of addresses in it.
type addressPool struct {
	as        *addressSpace
	Id        string
	IfName    string
	Subnet    net.IPNet
	Addresses map[string]*addressRecord
	IsIPv6    bool
	Priority  int
	InUse     bool
	epoch     int
}

// Represents an IP address in a pool.
type addressRecord struct {
	Addr  net.IP
	InUse bool
	epoch int
}

//
// AddressPoolId
//

// Creates a new address pool ID object.
func newAddressPoolId(asId string, subnet string, childSubnet string) *addressPoolId {
	return &addressPoolId{
		asId:        asId,
		subnet:      subnet,
		childSubnet: childSubnet,
	}
}

// Creates a new pool ID from a string representation.
func newAddressPoolIdFromString(s string) (*addressPoolId, error) {
	var pid addressPoolId

	p := strings.Split(s, "|")
	if len(p) > 3 {
		return nil, errInvalidPoolId
	}

	pid.asId = p[0]
	if len(p) >= 2 {
		pid.subnet = p[1]
	}
	if len(p) == 3 {
		pid.childSubnet = p[2]
	}

	return &pid, nil
}

// Returns the string representation of a pool ID.
func (pid *addressPoolId) String() string {
	s := fmt.Sprintf("%s|%s", pid.asId, pid.subnet)
	if pid.childSubnet != "" {
		s = fmt.Sprintf("%s|%s", s, pid.childSubnet)
	}
	return s
}

//
// AddressSpace
//

// Creates a new addressSpace object.
func (am *addressManager) newAddressSpace(id string, scope string) (*addressSpace, error) {
	if scope != localScope && scope != globalScope {
		return nil, errInvalidScope
	}

	return &addressSpace{
		Id:    id,
		Scope: scope,
		Pools: make(map[string]*addressPool),
	}, nil
}

// Returns the address space with the given ID.
func (am *addressManager) getAddressSpace(id string) (*addressSpace, error) {
	as := am.AddrSpaces[id]
	if as == nil {
		return nil, errInvalidAddressSpace
	}

	return as, nil
}

// Sets a new or updates an existing address space.
func (am *addressManager) setAddressSpace(as *addressSpace) error {
	as1, ok := am.AddrSpaces[as.Id]
	if !ok {
		am.AddrSpaces[as.Id] = as
	} else {
		as1.merge(as)
	}

	// Notify NetPlugin of external interfaces.
	for _, ap := range as.Pools {
		am.netApi.AddExternalInterface(ap.IfName, ap.Subnet.String())
	}

	am.save()

	return nil
}

// Merges a new address space to an existing one.
func (as *addressSpace) merge(newas *addressSpace) {
	// The new epoch after the merge.
	as.epoch++

	// Add new pools and addresses.
	for pk, pv := range newas.Pools {
		ap := as.Pools[pk]

		if ap == nil {
			// This is a new address pool.
			// Merge it to the existing address space.
			as.Pools[pk] = pv
			delete(newas.Pools, pk)
			pv.epoch = as.epoch
		} else {
			// This pool already exists.
			// Compare address records one by one.
			for ak, av := range pv.Addresses {
				ar := ap.Addresses[ak]

				if ar == nil {
					// This is a new address record.
					// Merge it to the existing address pool.
					ap.Addresses[ak] = av
					delete(ap.Addresses, ak)
					av.epoch = as.epoch
				} else {
					// This address record already exists.
					ar.epoch = as.epoch
				}
			}

			ap.epoch = as.epoch
		}
	}

	// Cleanup stale pools and addresses from the old epoch.
	// Those currently in use will be deleted after they are released.
	for pk, pv := range as.Pools {
		if pv.epoch < as.epoch {
			for ak, av := range pv.Addresses {
				if !av.InUse {
					delete(pv.Addresses, ak)
				}
			}

			if !pv.InUse {
				delete(as.Pools, pk)
			}
		}
	}

	return
}

// Creates a new addressPool object.
func (as *addressSpace) newAddressPool(ifName string, priority int, subnet *net.IPNet) (*addressPool, error) {
	id := subnet.String()

	pool, ok := as.Pools[id]
	if ok {
		return pool, errAddressPoolExists
	}

	v6 := (len(subnet.IP) > net.IPv4len)

	pool = &addressPool{
		as:        as,
		Id:        id,
		IfName:    ifName,
		Subnet:    *subnet,
		Addresses: make(map[string]*addressRecord),
		IsIPv6:    v6,
		Priority:  priority,
		epoch:     as.epoch,
	}

	as.Pools[id] = pool

	return pool, nil
}

// Returns the address pool with the given pool ID.
func (as *addressSpace) getAddressPool(poolId string) (*addressPool, error) {
	ap := as.Pools[poolId]
	if ap == nil {
		return nil, errInvalidPoolId
	}

	return ap, nil
}

// Requests a new address pool from the address space.<commit_msg>Fixed IP address family check<commit_after>// Copyright Microsoft Corp.
// All rights reserved.

package ipam

import (
	"fmt"
	"net"
	"strings"
)

const (
	// Default address space IDs.
	localDefaultAddressSpaceId  = "LocalDefaultAddressSpace"
	globalDefaultAddressSpaceId = "GlobalDefaultAddressSpace"

	// Address space scopes.
	localScope  = "local"
	globalScope = "global"
)

// Represents the key to an address pool.
type addressPoolId struct {
	asId        string
	subnet      string
	childSubnet string
}

// Represents a set of non-overlapping address pools.
type addressSpace struct {
	Id    string
	Scope string
	Pools map[string]*addressPool
	epoch int
}

// Represents a subnet and the set of addresses in it.
type addressPool struct {
	as        *addressSpace
	Id        string
	IfName    string
	Subnet    net.IPNet
	Addresses map[string]*addressRecord
	IsIPv6    bool
	Priority  int
	InUse     bool
	epoch     int
}

// Represents an IP address in a pool.
type addressRecord struct {
	Addr  net.IP
	InUse bool
	epoch int
}

//
// AddressPoolId
//

// Creates a new address pool ID object.
func newAddressPoolId(asId string, subnet string, childSubnet string) *addressPoolId {
	return &addressPoolId{
		asId:        asId,
		subnet:      subnet,
		childSubnet: childSubnet,
	}
}

// Creates a new pool ID from a string representation.
func newAddressPoolIdFromString(s string) (*addressPoolId, error) {
	var pid addressPoolId

	p := strings.Split(s, "|")
	if len(p) > 3 {
		return nil, errInvalidPoolId
	}

	pid.asId = p[0]
	if len(p) >= 2 {
		pid.subnet = p[1]
	}
	if len(p) == 3 {
		pid.childSubnet = p[2]
	}

	return &pid, nil
}

// Returns the string representation of a pool ID.
func (pid *addressPoolId) String() string {
	s := fmt.Sprintf("%s|%s", pid.asId, pid.subnet)
	if pid.childSubnet != "" {
		s = fmt.Sprintf("%s|%s", s, pid.childSubnet)
	}
	return s
}

//
// AddressSpace
//

// Creates a new addressSpace object.
func (am *addressManager) newAddressSpace(id string, scope string) (*addressSpace, error) {
	if scope != localScope && scope != globalScope {
		return nil, errInvalidScope
	}

	return &addressSpace{
		Id:    id,
		Scope: scope,
		Pools: make(map[string]*addressPool),
	}, nil
}

// Returns the address space with the given ID.
func (am *addressManager) getAddressSpace(id string) (*addressSpace, error) {
	as := am.AddrSpaces[id]
	if as == nil {
		return nil, errInvalidAddressSpace
	}

	return as, nil
}

// Sets a new or updates an existing address space.
func (am *addressManager) setAddressSpace(as *addressSpace) error {
	as1, ok := am.AddrSpaces[as.Id]
	if !ok {
		am.AddrSpaces[as.Id] = as
	} else {
		as1.merge(as)
	}

	// Notify NetPlugin of external interfaces.
	if am.netApi != nil {
		for _, ap := range as.Pools {
			am.netApi.AddExternalInterface(ap.IfName, ap.Subnet.String())
		}
	}

	am.save()

	return nil
}

// Merges a new address space to an existing one.
func (as *addressSpace) merge(newas *addressSpace) {
	// The new epoch after the merge.
	as.epoch++

	// Add new pools and addresses.
	for pk, pv := range newas.Pools {
		ap := as.Pools[pk]

		if ap == nil {
			// This is a new address pool.
			// Merge it to the existing address space.
			as.Pools[pk] = pv
			delete(newas.Pools, pk)
			pv.epoch = as.epoch
		} else {
			// This pool already exists.
			// Compare address records one by one.
			for ak, av := range pv.Addresses {
				ar := ap.Addresses[ak]

				if ar == nil {
					// This is a new address record.
					// Merge it to the existing address pool.
					ap.Addresses[ak] = av
					delete(ap.Addresses, ak)
					av.epoch = as.epoch
				} else {
					// This address record already exists.
					ar.epoch = as.epoch
				}
			}

			ap.epoch = as.epoch
		}
	}

	// Cleanup stale pools and addresses from the old epoch.
	// Those currently in use will be deleted after they are released.
	for pk, pv := range as.Pools {
		if pv.epoch < as.epoch {
			for ak, av := range pv.Addresses {
				if !av.InUse {
					delete(pv.Addresses, ak)
				}
			}

			if !pv.InUse {
				delete(as.Pools, pk)
			}
		}
	}

	return
}

// Creates a new addressPool object.
func (as *addressSpace) newAddressPool(ifName string, priority int, subnet *net.IPNet) (*addressPool, error) {
	id := subnet.String()

	pool, ok := as.Pools[id]
	if ok {
		return pool, errAddressPoolExists
	}

	v6 := (subnet.IP.To4() == nil)

	pool = &addressPool{
		as:        as,
		Id:        id,
		IfName:    ifName,
		Subnet:    *subnet,
		Addresses: make(map[string]*addressRecord),
		IsIPv6:    v6,
		Priority:  priority,
		epoch:     as.epoch,
	}

	as.Pools[id] = pool

	return pool, nil
}

// Returns the address pool with the given pool ID.
func (as *addressSpace) getAddressPool(poolId string) (*addressPool, error) {
	ap := as.Pools[poolId]
	if ap == nil {
		return nil, errInvalidPoolId
	}

	return ap, nil
}

// Requests a new address pool from the address space.
{'fraction_non_alphanumeric': 0.11380616108893665, 'fraction_numerical': 0.002660935421144202, 'mean_word_length': 2.9134961954345213, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1295899', 'n_tokens_mistral': 3694, 'n_tokens_neox': 3432, 'n_words': 1066}