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

Dualstack Network Support #549

Open
wants to merge 64 commits into
base: master
Choose a base branch
from
Open

Dualstack Network Support #549

wants to merge 64 commits into from

Conversation

majst01
Copy link
Contributor

@majst01 majst01 commented Jul 17, 2024

Closes #164

Actions Required

The ChildPrefixLength property was removed from the Partition Entity. Every TenantSupernetwork must now be configured with ChildPrefixLength accordingly.
This is done during startup in the database migration step and set to the same value as in the `Partition`.

It is required to add a defaultchildprefixlength property to the tenant super network in you configuration because otherwise the initial network creation will fail:
Sample:
  defaultchildprefixlength:
    IPv4: 22

Also ensure that all firewall-controllers are up-to-date in all firewalls before adding ipv6 prefixes to any of the exiting networks.

Depends on:

replaces #544

TODO:

  • add possibility to create machines in different networks like internet and tenant-network, but only from tenant-network IPs from both AF are acquired, but only ipv4 is possible from internet even if dualstack

@majst01 majst01 force-pushed the dualstack-support branch 4 times, most recently from 5919c8f to 0c53831 Compare July 23, 2024 07:47
@majst01 majst01 force-pushed the dualstack-support branch 7 times, most recently from d49d2c0 to b65c835 Compare July 25, 2024 09:50
@majst01 majst01 force-pushed the dualstack-support branch 3 times, most recently from 23a3d1e to 89096c0 Compare August 2, 2024 12:40
@majst01 majst01 force-pushed the dualstack-support branch 2 times, most recently from a3571a2 to d9667d3 Compare August 5, 2024 07:13
@@ -79,6 +80,21 @@ func (p *IPSearchQuery) generateTerm(rs *RethinkStore) *r.Term {
})
}

if p.AddressFamily != nil {
separator := "."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
separator := "."
var separator string

Comment on lines +55 to +67
if parsed.Addr().Is4() {
af = metal.IPv4AddressFamily
defaultChildPrefixLength[af] = 22
}
if parsed.Addr().Is6() {
af = metal.IPv6AddressFamily
defaultChildPrefixLength[af] = 64
}

if new.AddressFamilies == nil {
new.AddressFamilies = metal.AddressFamilies{}
}
new.AddressFamilies = metal.AddressFamilies{af}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only required for private super networks and for those it's probably enough just to take the value from the partition for IPv4 and 64 for IPv6.

@@ -154,6 +155,25 @@ func (p *NetworkSearchQuery) generateTerm(rs *RethinkStore) (*r.Term, error) {
})
}

if p.AddressFamily != nil {
separator := "."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
separator := "."
var separator string

separator = ":"
}

fmt.Printf("Separator:%s\n", separator)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fmt.Printf("Separator:%s\n", separator)

Comment on lines 163 to 177
if pfx.Addr().Is6() {
af = metal.IPv6AddressFamily
}
availableIPs := metal.AddressFamilyUsage{
af: usage.Msg.AvailableIps,
}
usedIPs := metal.AddressFamilyUsage{
af: usage.Msg.AcquiredIps,
}
availablePrefixes := metal.AddressFamilyUsage{
af: usage.Msg.AvailableSmallestPrefixes,
}
usedPrefixes := metal.AddressFamilyUsage{
af: usage.Msg.AcquiredPrefixes,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is always the same address family and the map will never have different ones it might be okay to just return the usage without address family and handle in the caller where to put it

@@ -258,6 +286,49 @@ func TestAllocateIP(t *testing.T) {
wantedStatus: http.StatusUnprocessableEntity,
wantErr: errors.New("specific ip not contained in any of the defined prefixes"),
},
{
name: "allocate a IPv4 address",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: "allocate a IPv4 address",
name: "allocate an IPv4 address",

wantedStatus: http.StatusCreated,
},
{
name: "allocate a IPv6 address",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: "allocate a IPv6 address",
name: "allocate an IPv6 address",

wantErr: errors.New("there is no prefix for the given addressfamily:IPv6 present in network:4"),
},
{
name: "allocate a IPv4 (no addressfamily specified) address from a IPv6 Only network",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: "allocate a IPv4 (no addressfamily specified) address from a IPv6 Only network",
name: "allocate an IPv4 (no addressfamily specified) address from an IPv6 only network",

if n == nil || n.network == nil {
continue
}
if len(n.network.AddressFamilies) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if this is possible but can this be dynamically evaluated where the network was retrieved?

Comment on lines 337 to 338
// We should support two private super per partition, one per addressfamily
// the network allocate request must be configurable with addressfamily
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// We should support two private super per partition, one per addressfamily
// the network allocate request must be configurable with addressfamily

PartitionID: &partition.ID,
PrivateSuper: pointer.Pointer(true),
}, &nw)
r.log.Info("createnetwork", "found", nw)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
r.log.Info("createnetwork", "found", nw)

@@ -439,6 +456,79 @@ func validateAdditionalAnnouncableCIDRs(additionalCidrs []string, privateSuper b
return nil
}

func validatePrefixesAndAddressFamilies(prefixes, destinationPrefixes []string, defaultChildPrefixLength metal.ChildPrefixLength, privateSuper bool) (metal.Prefixes, metal.Prefixes, metal.AddressFamilies, error) {
Copy link
Contributor

@Gerrit91 Gerrit91 Jan 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function signature does not imply the return values. Could be better to split validation functions from parsing functions to increase reusability.

if err != nil {
return nil, nil, nil, err
}
// all DestinationPrefixes must be valid and from the same addressfamily
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still correct? Because I see different address families in the destination prefixes in our test environment.

if err != nil {
return nil, nil, nil, err
}
if len(destinationAddressFamilies) > len(addressFamilies) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this check is insufficient, e.g. there are IPv6 destination prefixes but only IPv4 prefixes.

}

for af, length := range defaultChildPrefixLength {
fmt.Printf("af %s length:%d addressfamilies:%v", af, length, addressFamilies)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fmt.Printf("af %s length:%d addressfamilies:%v", af, length, addressFamilies)


prefixes = append(prefixes, *prefix)
var childPrefixLength = metal.ChildPrefixLength{}
for af, length := range requestPayload.DefaultChildPrefixLength {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either this needs only to be done for private super or the validation must be extended to validate this field for non-private super networks, too.

return
}
if len(superNetwork.DefaultChildPrefixLength) == 0 {
r.sendError(request, response, httperrors.BadRequest(fmt.Errorf("supernetwork %s has no defaultchildprefixlength specified", superNetwork.ID)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be an internal server error but I am not sure if we need these validation because we ensure this somewhere else in the code?

return nil, nil, nil, fmt.Errorf("private super network must always contain a defaultchildprefixlength")
}

for af, length := range defaultChildPrefixLength {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would also be good to check if the address family is actually IPv4 or IPv6.

r.sendError(request, response, httperrors.BadRequest(fmt.Errorf("supernetwork %s has no defaultchildprefixlength specified", superNetwork.ID)))
return
}
r.log.Info("network allocate", "supernetwork", superNetwork.ID)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log appears later in the code again

return nil, err
}
if childPrefix == nil {
return nil, fmt.Errorf("could not allocate child prefix in parent network: %s for addressfamily: %s length:%d", parent.ID, af, childLength)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to mitigate this but this is a potential leakage in case one child prefix could already be allocated.

)

// ToAddressFamily will convert a string af to a AddressFamily
func ToAddressFamily(af string) AddressFamily {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When returning an error with this function it would be helpful for validations because currently users can often try to send random stuff to the API and try to do something weird.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented ValidateAddressfamily as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

☂️-Issue IPv6 Support
4 participants