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

Merged
merged 81 commits into from
Feb 19, 2025
Merged
Changes from 1 commit
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
5ea7ea6
IPv6 Support
majst01 Jul 4, 2024
22d916e
More tests
majst01 Jul 4, 2024
e8571c9
Validate Prefixes and DestinationPrefixes on create and update network
majst01 Jul 7, 2024
59c7511
Constify defaultChildPrefixlength
majst01 Jul 7, 2024
9f52dfd
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Jul 8, 2024
89a0857
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Jul 9, 2024
aae9274
Support DualStack Networks
majst01 Jul 17, 2024
1b09d5d
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Jul 23, 2024
87a2a98
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Jul 24, 2024
23e4cbd
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Aug 5, 2024
a175469
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Aug 6, 2024
c519d3b
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Aug 7, 2024
a1575ef
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Aug 8, 2024
f553164
Merge master
majst01 Aug 13, 2024
fa47c76
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Aug 14, 2024
6430ea1
Make additional announcable cidrs configurable per tenant super network
majst01 Aug 14, 2024
5f3287e
Merge additionalannouncablecidrs in
majst01 Aug 16, 2024
1822069
Merge master
majst01 Aug 26, 2024
72ac513
satisfy linter
majst01 Aug 26, 2024
82cc73e
Merge master
majst01 Sep 5, 2024
d2cb195
sanitize go.mod
majst01 Sep 5, 2024
d408762
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Sep 10, 2024
8f06d84
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Sep 13, 2024
10f49c7
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Sep 29, 2024
88835d4
Merge branch 'master' into dualstack-support
majst01 Sep 30, 2024
02a518f
Merge master
majst01 Oct 2, 2024
44c8825
Remove false comment
majst01 Oct 2, 2024
fbe6a32
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Oct 2, 2024
7568f8e
Updates
majst01 Oct 7, 2024
9db0e6e
Merge master
majst01 Oct 8, 2024
84c63ad
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Oct 11, 2024
43dc320
Merge branch 'master' into dualstack-support
majst01 Nov 6, 2024
5719737
merge master
majst01 Nov 8, 2024
576df4a
Merge branch 'dualstack-support' of https://github.com/metal-stack/me…
majst01 Nov 8, 2024
2e72212
Introduce a type
majst01 Nov 8, 2024
f2da96e
Merge branch 'master' into dualstack-support
majst01 Nov 11, 2024
bd57dcb
Merge master
majst01 Nov 11, 2024
343ef3b
Merge branch 'master' into dualstack-support
majst01 Nov 11, 2024
f313f41
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Nov 12, 2024
4bb6603
Merge branch 'master' into dualstack-support
majst01 Nov 13, 2024
fbf1970
More consts
majst01 Nov 13, 2024
03c2436
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Nov 13, 2024
e726090
Merge branch 'master' into dualstack-support
majst01 Nov 19, 2024
c9c4b7e
Allow update DefaultChildPrefixLength
majst01 Jan 2, 2025
5e73c10
Do not allow mixed AddressFamilies in static firewall rules
majst01 Jan 10, 2025
3b7bb28
Better naming
majst01 Jan 10, 2025
a1a3428
If no Addressfamily is given during allocateIP in a ipv6 only network…
majst01 Jan 10, 2025
391d997
Better error messages on firewall rule validation
majst01 Jan 10, 2025
3fd8505
Simplify addressfamilies
majst01 Jan 13, 2025
3cc62cf
Better network usage
majst01 Jan 16, 2025
94bc6e8
Omit unused afs in consumption
majst01 Jan 16, 2025
ce53bcd
Fix test
majst01 Jan 16, 2025
a374b2c
Server side filtering by addressfamily for network and ip
majst01 Jan 18, 2025
6b2c3a8
Server side filtering by addressfamily for network and ip
majst01 Jan 18, 2025
9d1c340
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Jan 23, 2025
26a9b5e
Merge master
majst01 Jan 24, 2025
d3610e8
No addressfamilies in response
majst01 Jan 24, 2025
9ee694a
Fix typo
majst01 Jan 24, 2025
d964c1b
Update deps
majst01 Jan 27, 2025
04a84e5
Introduce helper function.
Gerrit91 Jan 29, 2025
e38db83
Fix ip query
majst01 Jan 29, 2025
60c9d8a
First bunch of review findings
majst01 Jan 30, 2025
0d64c98
Small fix
majst01 Jan 30, 2025
ff87efa
Validate Addressfamily
majst01 Jan 30, 2025
de2aee0
satisfy linter
majst01 Feb 3, 2025
2c79ab0
Better validation
majst01 Feb 3, 2025
66d8c71
Merge branch 'master' of https://github.com/metal-stack/metal-api int…
majst01 Feb 4, 2025
afd3f26
Small improvement
majst01 Feb 4, 2025
8a118c5
Better migration code
majst01 Feb 5, 2025
ce9b626
Linter fix
majst01 Feb 5, 2025
f2d560e
More validation
majst01 Feb 5, 2025
cd675fb
Merge branch 'master' into dualstack-support
Gerrit91 Feb 12, 2025
a21889e
Divide into validate and convert
majst01 Feb 13, 2025
7760e23
Add test for validation, and fix actual bug
majst01 Feb 13, 2025
b340472
Get rid of extra method to validate afs
majst01 Feb 17, 2025
76c3614
Do not store addressfamily in the network
majst01 Feb 17, 2025
091b132
Reuse existing conversions
majst01 Feb 17, 2025
df787e3
Reuse existing conversions
majst01 Feb 17, 2025
6b0fc18
Last fixes
majst01 Feb 17, 2025
84d154a
Fix linter config
majst01 Feb 17, 2025
ca9a6f4
merge master
majst01 Feb 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge master
  • Loading branch information
majst01 committed Sep 5, 2024
commit 82cc73e8cfca50c19e99577fb3e163090a8e8cd1
Original file line number Diff line number Diff line change
@@ -28,18 +28,27 @@ func init() {
if err != nil {
return err
}
if cursor.IsNil() {
_ = cursor.Close()
continue
}
var partition tmpPartition
err = cursor.One(&partition)
if err != nil {
_ = cursor.Close()
return err
}
err = cursor.Close()
if err != nil {
return err
}

new := old

var (
af metal.AddressFamily
defaultChildPrefixLength = metal.ChildPrefixLength{}
)
// FIXME check all prefixes
parsed, err := netip.ParsePrefix(new.Prefixes[0].String())
if err != nil {
return err
@@ -73,10 +82,6 @@ func init() {
if err != nil {
return err
}
err = cursor.Close()
if err != nil {
return err
}
}

_, err = db.Table("partition").Replace(r.Row.Without("privatenetworkprefixlength")).RunWrite(session)
Original file line number Diff line number Diff line change
@@ -23,14 +23,14 @@ import (
"github.com/stretchr/testify/require"
)

func Test_MigrationProvisioningEventContainer(t *testing.T) {
func Test_Migration(t *testing.T) {
container, c, err := test.StartRethink(t)
require.NoError(t, err)
defer func() {
_ = container.Terminate(context.Background())
}()

log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelError}))
log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))

rs := datastore.New(log, c.IP+":"+c.Port, c.DB, c.User, c.Password)
rs.VRFPoolRangeMin = 10000
45 changes: 21 additions & 24 deletions cmd/metal-api/internal/service/network-service.go
Original file line number Diff line number Diff line change
@@ -7,6 +7,8 @@ import (
"log/slog"
"net/http"
"net/netip"
"slices"
"strconv"

"connectrpc.com/connect"
mdmv1 "github.com/metal-stack/masterdata-api/api/v1"
@@ -370,7 +372,7 @@ func (r *networkResource) createNetwork(request *restful.Request, response *rest
return
}

additionalAnnouncableCIDRs, err := validateAdditionalAnnouncableCIDRs(requestPayload.AdditionalAnnouncableCIDRs, privateSuper)
err = validateAdditionalAnnouncableCIDRs(requestPayload.AdditionalAnnouncableCIDRs, privateSuper)
if err != nil {
r.sendError(request, response, httperrors.BadRequest(err))
return
@@ -407,7 +409,7 @@ func (r *networkResource) createNetwork(request *restful.Request, response *rest
Vrf: vrf,
Labels: labels,
AddressFamilies: addressFamilies,
AdditionalAnnouncableCIDRs: additionalAnnouncableCIDRs,
AdditionalAnnouncableCIDRs: requestPayload.AdditionalAnnouncableCIDRs,
}

ctx := request.Request.Context()
@@ -434,21 +436,23 @@ func (r *networkResource) createNetwork(request *restful.Request, response *rest
r.send(request, response, http.StatusCreated, v1.NewNetworkResponse(nw, usage))
}

func validateAdditionalAnnouncableCIDRs(additionalCidrs []string, privateSuper bool) ([]string, error) {
var result []string
if len(additionalCidrs) > 0 {
if !privateSuper {
return nil, errors.New("additionalannouncablecidrs can only be set in a private super network")
}
for _, cidr := range additionalCidrs {
_, err := netip.ParsePrefix(cidr)
if err != nil {
return nil, fmt.Errorf("given cidr:%q in additionalannouncablecidrs is malformed:%w", cidr, err)
}
result = append(result, cidr)
func validateAdditionalAnnouncableCIDRs(additionalCidrs []string, privateSuper bool) error {
if len(additionalCidrs) == 0 {
return nil
}

if !privateSuper {
return errors.New("additionalannouncablecidrs can only be set in a private super network")
}

for _, cidr := range additionalCidrs {
_, err := netip.ParsePrefix(cidr)
if err != nil {
return fmt.Errorf("given cidr:%q in additionalannouncablecidrs is malformed:%w", cidr, err)
}
}
return result, nil

return nil
}

func validatePrefixesAndAddressFamilies(prefixes, destinationPrefixes []string, defaultChildPrefixLength metal.ChildPrefixLength, privateSuper bool) (metal.Prefixes, metal.Prefixes, metal.AddressFamilies, error) {
@@ -859,19 +863,12 @@ func (r *networkResource) updateNetwork(request *restful.Request, response *rest
}
}

additionalRouteMapCIDRs, err := validateAdditionalAnnouncableCIDRs(requestPayload.AdditionalAnnouncableCIDRs, oldNetwork.PrivateSuper)
err = validateAdditionalAnnouncableCIDRs(requestPayload.AdditionalAnnouncableCIDRs, oldNetwork.PrivateSuper)
if err != nil {
r.sendError(request, response, defaultError(err))
return
}
newNetwork.AdditionalAnnouncableCIDRs = additionalRouteMapCIDRs

additionalAnnouncableCIDRs, err := validateAdditionalAnnouncableCIDRs(requestPayload.AdditionalAnnouncableCIDRs, oldNetwork.PrivateSuper)
if err != nil {
r.sendError(request, response, httperrors.BadRequest(err))
return
}
newNetwork.AdditionalAnnouncableCIDRs = additionalAnnouncableCIDRs
newNetwork.AdditionalAnnouncableCIDRs = requestPayload.AdditionalAnnouncableCIDRs

err = validateAdditionalAnnouncableCIDRs(requestPayload.AdditionalAnnouncableCIDRs, oldNetwork.PrivateSuper)
if err != nil {
44 changes: 21 additions & 23 deletions cmd/metal-api/internal/service/switch-service.go
Original file line number Diff line number Diff line change
@@ -773,12 +773,12 @@ func updateSwitchNics(oldNics, newNics map[string]*metal.Nic, currentConnections
}

func (r *switchResource) makeSwitchResponse(s *metal.Switch) (*v1.SwitchResponse, error) {
p, ips, machines, ss, err := findSwitchReferencedEntities(s, r.ds)
p, nws, ips, machines, ss, err := r.findSwitchReferencedEntities(s)
if err != nil {
return nil, err
}

nics, err := r.makeSwitchNics(s, ips, machines)
nics, err := r.makeSwitchNics(s, nws, ips, machines)
if err != nil {
return nil, err
}
@@ -809,7 +809,7 @@ func (r *switchResource) makeBGPFilterFirewall(m metal.Machine) (v1.BGPFilter, e
return v1.NewBGPFilter(vnis, cidrs), nil
}

func (r *switchResource) makeBGPFilterMachine(m metal.Machine, ips metal.IPsMap) (v1.BGPFilter, error) {
func (r *switchResource) makeBGPFilterMachine(m metal.Machine, nws metal.NetworkMap, ips metal.IPsMap) (v1.BGPFilter, error) {
vnis := []string{}
cidrs := []string{}

@@ -827,21 +827,19 @@ func (r *switchResource) makeBGPFilterMachine(m metal.Machine, ips metal.IPsMap)
if private != nil {
cidrs = append(cidrs, private.Prefixes...)

privateNetwork, err := r.ds.FindNetworkByID(private.NetworkID)
if err != nil && !metal.IsNotFound(err) {
return v1.BGPFilter{}, err
privateNetwork, ok := nws[private.NetworkID]
if !ok {
return v1.BGPFilter{}, fmt.Errorf("no private network found for ID:%s", private.NetworkID)
}
if privateNetwork != nil {
parentNetwork, err := r.ds.FindNetworkByID(privateNetwork.ParentNetworkID)
if err != nil && !metal.IsNotFound(err) {
return v1.BGPFilter{}, err
}
// Only for private networks, AdditionalAnnouncableCIDRs are applied.
// they contain usually the pod- and service- cidrs in a kubernetes cluster
if parentNetwork != nil && len(parentNetwork.AdditionalAnnouncableCIDRs) > 0 {
r.log.Debug("makeBGPFilterMachine", "additional cidrs", parentNetwork.AdditionalAnnouncableCIDRs)
cidrs = append(cidrs, parentNetwork.AdditionalAnnouncableCIDRs...)
}
parentNetwork, ok := nws[privateNetwork.ParentNetworkID]
if !ok {
return v1.BGPFilter{}, fmt.Errorf("no parent network found for ID:%s", privateNetwork.ParentNetworkID)
}
// Only for private networks, AdditionalAnnouncableCIDRs are applied.
// they contain usually the pod- and service- cidrs in a kubernetes cluster
if len(parentNetwork.AdditionalAnnouncableCIDRs) > 0 {
r.log.Debug("makeBGPFilterMachine", "additional cidrs", parentNetwork.AdditionalAnnouncableCIDRs)
cidrs = append(cidrs, parentNetwork.AdditionalAnnouncableCIDRs...)
}
}
for _, i := range ips[m.Allocation.Project] {
@@ -901,7 +899,7 @@ func compactCidrs(cidrs []string) ([]string, error) {
return compactedCidrs, nil
}

func (r *switchResource) makeBGPFilter(m metal.Machine, vrf string, ips metal.IPsMap) (v1.BGPFilter, error) {
func (r *switchResource) makeBGPFilter(m metal.Machine, vrf string, nws metal.NetworkMap, ips metal.IPsMap) (v1.BGPFilter, error) {
var (
filter v1.BGPFilter
err error
@@ -914,13 +912,13 @@ func (r *switchResource) makeBGPFilter(m metal.Machine, vrf string, ips metal.IP
filter, err = r.makeBGPFilterFirewall(m)
}
} else {
filter, err = r.makeBGPFilterMachine(m, ips)
filter, err = r.makeBGPFilterMachine(m, nws, ips)
}

return filter, err
}

func (r *switchResource) makeSwitchNics(s *metal.Switch, ips metal.IPsMap, machines metal.Machines) (v1.SwitchNics, error) {
func (r *switchResource) makeSwitchNics(s *metal.Switch, nws metal.NetworkMap, ips metal.IPsMap, machines metal.Machines) (v1.SwitchNics, error) {
machinesByID := map[string]*metal.Machine{}
for i, m := range machines {
machinesByID[m.ID] = &machines[i]
@@ -941,7 +939,7 @@ func (r *switchResource) makeSwitchNics(s *metal.Switch, ips metal.IPsMap, machi
m := machinesBySwp[n.Name]
var filter *v1.BGPFilter
if m != nil && m.Allocation != nil {
f, err := r.makeBGPFilter(*m, n.Vrf, ips)
f, err := r.makeBGPFilter(*m, n.Vrf, nws, ips)
if err != nil {
return nil, err
}
@@ -1051,7 +1049,7 @@ func (r *switchResource) findSwitchReferencedEntities(s *metal.Switch) (*metal.P
}

func (r *switchResource) makeSwitchResponseList(ss metal.Switches) ([]*v1.SwitchResponse, error) {
pMap, ips, err := getSwitchReferencedEntityMaps(r.ds)
pMap, nws, ips, err := getSwitchReferencedEntityMaps(r.ds)
if err != nil {
return nil, err
}
@@ -1070,7 +1068,7 @@ func (r *switchResource) makeSwitchResponseList(ss metal.Switches) ([]*v1.Switch
p = &partitionEntity
}

nics, err := r.makeSwitchNics(&sw, ips, m)
nics, err := r.makeSwitchNics(&sw, nws, ips, m)
if err != nil {
return nil, err
}
4 changes: 2 additions & 2 deletions cmd/metal-api/internal/service/switch-service_test.go
Original file line number Diff line number Diff line change
@@ -525,7 +525,7 @@ func TestMakeBGPFilterMachine(t *testing.T) {

r := switchResource{webResource: webResource{ds: ds, log: slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))}}

got, _ := r.makeBGPFilterMachine(tt.args.machine, tt.args.ipsMap)
got, _ := r.makeBGPFilterMachine(tt.args.machine, tt.args.nws, tt.args.ipsMap)

if !reflect.DeepEqual(got, tt.want) {
t.Errorf("makeBGPFilterMachine() = %v, want %v", got, tt.want)
@@ -635,7 +635,7 @@ func TestMakeSwitchNics(t *testing.T) {
tt := tests[i]
t.Run(tt.name, func(t *testing.T) {
r := switchResource{}
got, _ := r.makeSwitchNics(tt.args.s, tt.args.ips, tt.args.machines)
got, _ := r.makeSwitchNics(tt.args.s, tt.args.nws, tt.args.ips, tt.args.machines)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("makeSwitchNics() = %v, want %v", got, tt.want)
}
4 changes: 2 additions & 2 deletions cmd/metal-api/internal/service/v1/network.go
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ type NetworkImmutable struct {
VrfShared *bool `json:"vrfshared" description:"if set to true, given vrf can be used by multiple networks, which is sometimes useful for network partitioning (default: false)" optional:"true"`
ParentNetworkID *string `json:"parentnetworkid" description:"the id of the parent network" optional:"true"`
AddressFamilies metal.AddressFamilies `json:"addressfamilies" description:"the addressfamilies in this network, either IPv4 or IPv6 or both"`
AdditionalAnnouncableCIDRs []string `json:"additionalannouncablecidrs" description:"list of cidrs which are added to the route maps per tenant private network, these are typically pod- and service cidrs, can only be set in a supernetwork" optional:"true"`
AdditionalAnnouncableCIDRs []string `json:"additionalAnnouncableCIDRs,omitempty" description:"list of cidrs which are added to the route maps per tenant private network, these are typically pod- and service cidrs, can only be set for private super networks"`
}

// NetworkUsage reports core metrics about available and used IPs or Prefixes in a Network.
@@ -67,7 +67,7 @@ type NetworkUpdateRequest struct {
DestinationPrefixes []string `json:"destinationprefixes" description:"the destination prefixes of this network" optional:"true"`
Labels map[string]string `json:"labels" description:"free labels that you associate with this network." optional:"true"`
Shared *bool `json:"shared" description:"marks a network as shareable." optional:"true"`
AdditionalAnnouncableCIDRs []string `json:"additionalannouncablecidrs" description:"list of cidrs which are added to the route maps per tenant private network, these are typically pod- and service cidrs, can only be set in a supernetwork" optional:"true"`
AdditionalAnnouncableCIDRs []string `json:"additionalAnnouncableCIDRs" description:"list of cidrs which are added to the route maps per tenant private network, these are typically pod- and service cidrs, can only be set for private super networks" optional:"true"`
}

// NetworkResponse holds all properties returned in a FindNetwork or GetNetwork request.
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.