mirror of
https://github.com/danderson/netboot.git
synced 2025-10-17 02:21:20 +02:00
Added handling of multiple IANAs per solicit/request/release message
This commit is contained in:
parent
f89f6af9a6
commit
1cf3ef9b5b
@ -13,6 +13,6 @@ type IdentityAssociation struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AddressPool interface {
|
type AddressPool interface {
|
||||||
ReserveAddress(clientId, interfaceId []byte) *IdentityAssociation
|
ReserveAddresses(clientId []byte, interfaceIds [][]byte) []*IdentityAssociation
|
||||||
ReleaseAddress(clientId, interfaceId []byte)
|
ReleaseAddresses(clientId []byte, interfaceIds [][]byte)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ func MakeOption(id uint16, value []byte) *Option {
|
|||||||
return &Option{ Id: id, Length: uint16(len(value)), Value: value}
|
return &Option{ Id: id, Length: uint16(len(value)), Value: value}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Options map[uint16]*Option
|
type Options map[uint16][]*Option
|
||||||
|
|
||||||
func MakeOptions(bs []byte) (Options, error) {
|
func MakeOptions(bs []byte) (Options, error) {
|
||||||
to_ret := make(Options)
|
to_ret := make(Options)
|
||||||
@ -54,7 +54,6 @@ func MakeOptions(bs []byte) (Options, error) {
|
|||||||
switch optionId {
|
switch optionId {
|
||||||
// parse client_id
|
// parse client_id
|
||||||
// parse server_id
|
// parse server_id
|
||||||
// parse IaNa # do I need to support IaTa?
|
|
||||||
//parse ipaddr
|
//parse ipaddr
|
||||||
case OptOro:
|
case OptOro:
|
||||||
if optionLength% 2 != 0 {
|
if optionLength% 2 != 0 {
|
||||||
@ -66,7 +65,10 @@ func MakeOptions(bs []byte) (Options, error) {
|
|||||||
return nil, fmt.Errorf("option %d claims to have %d bytes of payload, but only has %d bytes", optionId, optionLength, len(bs[4:]))
|
return nil, fmt.Errorf("option %d claims to have %d bytes of payload, but only has %d bytes", optionId, optionLength, len(bs[4:]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
to_ret[optionId] = &Option{ Id: optionId, Length: optionLength, Value: bs[4 : 4+optionLength]}
|
_, present := to_ret[optionId]; if !present {
|
||||||
|
to_ret[optionId] = make([]*Option, 1)
|
||||||
|
}
|
||||||
|
to_ret[optionId] = append(to_ret[optionId], &Option{ Id: optionId, Length: optionLength, Value: bs[4 : 4+optionLength]})
|
||||||
bs = bs[4+optionLength:]
|
bs = bs[4+optionLength:]
|
||||||
}
|
}
|
||||||
return to_ret, nil
|
return to_ret, nil
|
||||||
@ -74,12 +76,14 @@ func MakeOptions(bs []byte) (Options, error) {
|
|||||||
|
|
||||||
func (o Options) HumanReadable() []string {
|
func (o Options) HumanReadable() []string {
|
||||||
to_ret := make([]string, 0, len(o))
|
to_ret := make([]string, 0, len(o))
|
||||||
for _, opt := range(o) {
|
for _, multipleOptions := range(o) {
|
||||||
switch opt.Id {
|
for _, option := range(multipleOptions) {
|
||||||
case 3:
|
switch option.Id {
|
||||||
to_ret = append(to_ret, o.HumanReadableIaNa(*opt)...)
|
case 3:
|
||||||
default:
|
to_ret = append(to_ret, o.HumanReadableIaNa(*option)...)
|
||||||
to_ret = append(to_ret, fmt.Sprintf("Option: %d | %d | %d | %s\n", opt.Id, opt.Length, opt.Value, opt.Value))
|
default:
|
||||||
|
to_ret = append(to_ret, fmt.Sprintf("Option: %d | %d | %d | %s\n", option.Id, option.Length, option.Value, option.Value))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return to_ret
|
return to_ret
|
||||||
@ -118,7 +122,10 @@ func (o Options) HumanReadableIaNa(opt Option) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o Options) AddOption(option *Option) {
|
func (o Options) AddOption(option *Option) {
|
||||||
o[option.Id] = option
|
_, present := o[option.Id]; if !present {
|
||||||
|
o[option.Id] = make([]*Option, 1)
|
||||||
|
}
|
||||||
|
o[option.Id] = append(o[option.Id], option)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaAddr *Option) (*Option) {
|
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaAddr *Option) (*Option) {
|
||||||
@ -141,13 +148,15 @@ func MakeIaAddrOption(addr net.IP, preferredLifetime, validLifetime uint32) (*Op
|
|||||||
|
|
||||||
func (o Options) Marshal() ([]byte, error) {
|
func (o Options) Marshal() ([]byte, error) {
|
||||||
buffer := bytes.NewBuffer(make([]byte, 0, 1446))
|
buffer := bytes.NewBuffer(make([]byte, 0, 1446))
|
||||||
for _, v := range(o) {
|
for _, multipleOptions := range(o) {
|
||||||
serialized, err := v.Marshal()
|
for _, o := range (multipleOptions) {
|
||||||
if err != nil {
|
serialized, err := o.Marshal()
|
||||||
return nil, fmt.Errorf("Error serializing option value: %s", err)
|
if err != nil {
|
||||||
}
|
return nil, fmt.Errorf("Error serializing option value: %s", err)
|
||||||
if err := binary.Write(buffer, binary.BigEndian, serialized); err != nil {
|
}
|
||||||
return nil, fmt.Errorf("Error serializing option value: %s", err)
|
if err := binary.Write(buffer, binary.BigEndian, serialized); err != nil {
|
||||||
|
return nil, fmt.Errorf("Error serializing option value: %s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buffer.Bytes(), nil
|
return buffer.Bytes(), nil
|
||||||
@ -178,8 +187,8 @@ func (o Options) UnmarshalOptionRequestOption() map[uint16]bool {
|
|||||||
return to_ret
|
return to_ret
|
||||||
}
|
}
|
||||||
|
|
||||||
oro_content := o[OptOro].Value
|
oro_content := o[OptOro][0].Value
|
||||||
for i := 0; i < int(o[OptOro].Length)/2; i++ {
|
for i := 0; i < int(o[OptOro][0].Length)/2; i++ {
|
||||||
to_ret[uint16(binary.BigEndian.Uint16(oro_content[i*2:(i+1)*2]))] = true
|
to_ret[uint16(binary.BigEndian.Uint16(oro_content[i*2:(i+1)*2]))] = true
|
||||||
}
|
}
|
||||||
return to_ret
|
return to_ret
|
||||||
@ -219,15 +228,27 @@ func (o Options) HasClientArchType() bool {
|
|||||||
func (o Options) ClientId() []byte {
|
func (o Options) ClientId() []byte {
|
||||||
opt, exists := o[OptClientId]
|
opt, exists := o[OptClientId]
|
||||||
if exists {
|
if exists {
|
||||||
return opt.Value
|
return opt[0].Value
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Options) IaNaId() []byte {
|
func (o Options) ServerId() []byte {
|
||||||
opt, exists := o[OptIaNa]
|
opt, exists := o[OptServerId]
|
||||||
if exists {
|
if exists {
|
||||||
return opt.Value[0:4]
|
return opt[0].Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Options) IaNaIds() [][]byte {
|
||||||
|
options, exists := o[OptIaNa]
|
||||||
|
if exists {
|
||||||
|
ret := make([][]byte, len(options))
|
||||||
|
for _, option := range(options) {
|
||||||
|
ret = append(ret, option.Value[0:4])
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -235,7 +256,7 @@ func (o Options) IaNaId() []byte {
|
|||||||
func (o Options) ClientArchType() uint16 {
|
func (o Options) ClientArchType() uint16 {
|
||||||
opt, exists := o[OptClientArchType]
|
opt, exists := o[OptClientArchType]
|
||||||
if exists {
|
if exists {
|
||||||
return binary.BigEndian.Uint16(opt.Value)
|
return binary.BigEndian.Uint16(opt[0].Value)
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ func ShouldDiscardRequest(p *Packet, serverDuid []byte) error {
|
|||||||
if !options.HasServerId() {
|
if !options.HasServerId() {
|
||||||
return fmt.Errorf("'Request' packet has no server id option")
|
return fmt.Errorf("'Request' packet has no server id option")
|
||||||
}
|
}
|
||||||
if bytes.Compare(options[OptServerId].Value, serverDuid) != 0 {
|
if bytes.Compare(options.ServerId(), serverDuid) != 0 {
|
||||||
return fmt.Errorf("'Request' packet's server id option (%d) is different from ours (%d)", options[OptServerId].Value, serverDuid)
|
return fmt.Errorf("'Request' packet's server id option (%d) is different from ours (%d)", options[OptServerId].Value, serverDuid)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -122,7 +122,7 @@ func ShouldDiscardInformationRequest(p *Packet, serverDuid []byte) error {
|
|||||||
if options.HasIaNa() || options.HasIaTa() {
|
if options.HasIaNa() || options.HasIaTa() {
|
||||||
return fmt.Errorf("'Information-request' packet has an IA option present")
|
return fmt.Errorf("'Information-request' packet has an IA option present")
|
||||||
}
|
}
|
||||||
if options.HasServerId() && (bytes.Compare(options[OptServerId].Value, serverDuid) != 0) {
|
if options.HasServerId() && (bytes.Compare(options.ServerId(), serverDuid) != 0) {
|
||||||
return fmt.Errorf("'Information-request' packet's server id option (%d) is different from ours (%d)", options[OptServerId].Value, serverDuid)
|
return fmt.Errorf("'Information-request' packet's server id option (%d) is different from ours (%d)", options[OptServerId].Value, serverDuid)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -132,21 +132,21 @@ func (b *PacketBuilder) BuildResponse(in *Packet) (*Packet, error) {
|
|||||||
|
|
||||||
switch in.Type {
|
switch in.Type {
|
||||||
case MsgSolicit:
|
case MsgSolicit:
|
||||||
association := b.Addresses.ReserveAddress(in.Options.ClientId(), in.Options.IaNaId())
|
|
||||||
bootFileUrl, err := b.Configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType())
|
bootFileUrl, err := b.Configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return b.MakeMsgAdvertise(in.TransactionID, in.Options.ClientId(), in.Options.IaNaId(),
|
associations := b.Addresses.ReserveAddresses(in.Options.ClientId(), in.Options.IaNaIds())
|
||||||
in.Options.ClientArchType(), association.IpAddress, bootFileUrl, b.Configuration.GetPreference()), nil
|
return b.MakeMsgAdvertise(in.TransactionID, in.Options.ClientId(),
|
||||||
|
in.Options.ClientArchType(), associations, bootFileUrl, b.Configuration.GetPreference()), nil
|
||||||
case MsgRequest:
|
case MsgRequest:
|
||||||
association := b.Addresses.ReserveAddress(in.Options.ClientId(), in.Options.IaNaId())
|
|
||||||
bootFileUrl, err := b.Configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType())
|
bootFileUrl, err := b.Configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return b.MakeMsgReply(in.TransactionID, in.Options.ClientId(), in.Options.IaNaId(),
|
associations := b.Addresses.ReserveAddresses(in.Options.ClientId(), in.Options.IaNaIds())
|
||||||
in.Options.ClientArchType(), association.IpAddress, bootFileUrl), nil
|
return b.MakeMsgReply(in.TransactionID, in.Options.ClientId(),
|
||||||
|
in.Options.ClientArchType(), associations, bootFileUrl), nil
|
||||||
case MsgInformationRequest:
|
case MsgInformationRequest:
|
||||||
bootFileUrl, err := b.Configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType())
|
bootFileUrl, err := b.Configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,19 +155,21 @@ func (b *PacketBuilder) BuildResponse(in *Packet) (*Packet, error) {
|
|||||||
return b.MakeMsgInformationRequestReply(in.TransactionID, in.Options.ClientId(),
|
return b.MakeMsgInformationRequestReply(in.TransactionID, in.Options.ClientId(),
|
||||||
in.Options.ClientArchType(), bootFileUrl), nil
|
in.Options.ClientArchType(), bootFileUrl), nil
|
||||||
case MsgRelease:
|
case MsgRelease:
|
||||||
b.Addresses.ReleaseAddress(in.Options.ClientId(), in.Options.IaNaId())
|
b.Addresses.ReleaseAddresses(in.Options.ClientId(), in.Options.IaNaIds())
|
||||||
return b.MakeMsgReleaseReply(in.TransactionID, in.Options.ClientId()), nil
|
return b.MakeMsgReleaseReply(in.TransactionID, in.Options.ClientId()), nil
|
||||||
default:
|
default:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId, iaId []byte, clientArchType uint16, ipAddress,
|
func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId []byte, clientArchType uint16,
|
||||||
bootFileUrl, preference []byte) *Packet {
|
associations []*IdentityAssociation, bootFileUrl, preference []byte) *Packet {
|
||||||
ret_options := make(Options)
|
ret_options := make(Options)
|
||||||
ret_options.AddOption(MakeOption(OptClientId, clientId))
|
ret_options.AddOption(MakeOption(OptClientId, clientId))
|
||||||
ret_options.AddOption(MakeIaNaOption(iaId, b.calculateT1(), b.calculateT2(),
|
for _, association := range(associations) {
|
||||||
MakeIaAddrOption(ipAddress, b.PreferredLifetime, b.ValidLifetime)))
|
ret_options.AddOption(MakeIaNaOption(association.InterfaceId, b.calculateT1(), b.calculateT2(),
|
||||||
|
MakeIaAddrOption(association.IpAddress, b.PreferredLifetime, b.ValidLifetime)))
|
||||||
|
}
|
||||||
ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid))
|
ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid))
|
||||||
if 0x10 == clientArchType { // HTTPClient
|
if 0x10 == clientArchType { // HTTPClient
|
||||||
ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
||||||
@ -175,18 +177,20 @@ func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId, iaId [
|
|||||||
ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl))
|
ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl))
|
||||||
if preference != nil {ret_options.AddOption(MakeOption(OptPreference, preference))}
|
if preference != nil {ret_options.AddOption(MakeOption(OptPreference, preference))}
|
||||||
|
|
||||||
// ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
|
//ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
|
||||||
//ret_options.AddOption(OptBootfileParam, []byte("http://")
|
//ret_options.AddOption(OptBootfileParam, []byte("http://")
|
||||||
|
|
||||||
return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options}
|
return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId, iaId []byte, clientArchType uint16, ipAddress,
|
func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId []byte, clientArchType uint16,
|
||||||
bootFileUrl []byte) *Packet {
|
associations []*IdentityAssociation, bootFileUrl []byte) *Packet {
|
||||||
ret_options := make(Options)
|
ret_options := make(Options)
|
||||||
ret_options.AddOption(MakeOption(OptClientId, clientId))
|
ret_options.AddOption(MakeOption(OptClientId, clientId))
|
||||||
ret_options.AddOption(MakeIaNaOption(iaId, b.calculateT1(), b.calculateT2(),
|
for _, association := range(associations) {
|
||||||
MakeIaAddrOption(ipAddress, b.PreferredLifetime, b.ValidLifetime)))
|
ret_options.AddOption(MakeIaNaOption(association.InterfaceId, b.calculateT1(), b.calculateT2(),
|
||||||
|
MakeIaAddrOption(association.IpAddress, b.PreferredLifetime, b.ValidLifetime)))
|
||||||
|
}
|
||||||
ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid))
|
ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid))
|
||||||
if 0x10 == clientArchType { // HTTPClient
|
if 0x10 == clientArchType { // HTTPClient
|
||||||
ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
||||||
|
@ -75,45 +75,54 @@ func NewRandomAddressPool(poolStartAddress, poolEndAddress net.IP, validLifetime
|
|||||||
return to_ret
|
return to_ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RandomAddressPool) ReserveAddress(clientId, interfaceId []byte) *IdentityAssociation {
|
func (p *RandomAddressPool) ReserveAddresses(clientId []byte, interfaceIds [][]byte) []*IdentityAssociation {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
clientIdHash := p.calculateIaIdHash(clientId, interfaceId)
|
ret := make([]*IdentityAssociation, len(interfaceIds))
|
||||||
association, exists := p.identityAssociations[clientIdHash]; if exists {
|
|
||||||
return association
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
for _, interfaceId := range (interfaceIds) {
|
||||||
rng := rand.New(rand.NewSource(p.timeNow().UnixNano()))
|
clientIdHash := p.calculateIaIdHash(clientId, interfaceId)
|
||||||
// we assume that ip addresses adhere to high 64 bits for net and subnet ids, low 64 bits are for host id rule
|
association, exists := p.identityAssociations[clientIdHash];
|
||||||
hostOffset := rng.Uint64()%(p.poolEndAddress.Uint64() - p.poolStartAddress.Uint64() + 1)
|
if exists {
|
||||||
newIp := big.NewInt(0).Add(p.poolStartAddress, big.NewInt(0).SetUint64(hostOffset))
|
ret = append(ret, association)
|
||||||
_, exists := p.usedIps[newIp.Uint64()]; if !exists {
|
continue
|
||||||
timeNow := p.timeNow()
|
}
|
||||||
to_ret := &IdentityAssociation{ClientId: clientId,
|
|
||||||
InterfaceId: interfaceId,
|
for {
|
||||||
IpAddress: newIp.Bytes(),
|
rng := rand.New(rand.NewSource(p.timeNow().UnixNano()))
|
||||||
CreatedAt: timeNow }
|
// we assume that ip addresses adhere to high 64 bits for net and subnet ids, low 64 bits are for host id rule
|
||||||
p.identityAssociations[clientIdHash] = to_ret
|
hostOffset := rng.Uint64() % (p.poolEndAddress.Uint64() - p.poolStartAddress.Uint64() + 1)
|
||||||
p.usedIps[newIp.Uint64()] = struct{}{}
|
newIp := big.NewInt(0).Add(p.poolStartAddress, big.NewInt(0).SetUint64(hostOffset))
|
||||||
p.identityAssociationExpirations.Push(&AssociationExpiration{expiresAt: p.calculateAssociationExpiration(timeNow), ia: to_ret})
|
_, exists := p.usedIps[newIp.Uint64()];
|
||||||
return to_ret
|
if !exists {
|
||||||
|
timeNow := p.timeNow()
|
||||||
|
association := &IdentityAssociation{ClientId: clientId,
|
||||||
|
InterfaceId: interfaceId,
|
||||||
|
IpAddress: newIp.Bytes(),
|
||||||
|
CreatedAt: timeNow}
|
||||||
|
p.identityAssociations[clientIdHash] = association
|
||||||
|
p.usedIps[newIp.Uint64()] = struct{}{}
|
||||||
|
p.identityAssociationExpirations.Push(&AssociationExpiration{expiresAt: p.calculateAssociationExpiration(timeNow), ia: association})
|
||||||
|
ret = append(ret, association)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RandomAddressPool) ReleaseAddress(clientId, interfaceId []byte) {
|
func (p *RandomAddressPool) ReleaseAddresses(clientId []byte, interfaceIds [][]byte) {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
association, exists := p.identityAssociations[p.calculateIaIdHash(clientId, interfaceId)]
|
for _, interfaceId := range(interfaceIds) {
|
||||||
if !exists {
|
association, exists := p.identityAssociations[p.calculateIaIdHash(clientId, interfaceId)]
|
||||||
return
|
if !exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(p.usedIps, big.NewInt(0).SetBytes(association.IpAddress).Uint64())
|
||||||
|
delete(p.identityAssociations, p.calculateIaIdHash(clientId, interfaceId))
|
||||||
}
|
}
|
||||||
delete(p.usedIps, big.NewInt(0).SetBytes(association.IpAddress).Uint64())
|
|
||||||
delete(p.identityAssociations, p.calculateIaIdHash(clientId, interfaceId))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RandomAddressPool) ExpireIdentityAssociations() {
|
func (p *RandomAddressPool) ExpireIdentityAssociations() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user