From 4ab8042f779d0baffb76a346bf45e96a2629919b Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Wed, 11 Sep 2024 10:51:39 +0200 Subject: [PATCH] IPv6 Support (#127) --- Dockerfile | 3 +- cmd/config.go | 1 + cmd/internal/core/core.go | 7 +- cmd/internal/core/reconfigure-switch.go | 24 ++--- cmd/internal/core/reconfigure-switch_test.go | 32 ++++--- .../switcher/templates/template_test.go | 17 +++- .../templates/test_data/dev/conf.yaml | 4 + .../templates/test_data/dev/cumulus_frr.conf | 21 ++++- .../test_data/dev/customtpl/frr.conf | 7 +- .../templates/test_data/dev/customtpl/frr.tpl | 1 + .../templates/test_data/dev/sonic_frr.conf | 25 ++++- .../templates/test_data/lab/conf.yaml | 2 + .../templates/test_data/lab/cumulus_frr.conf | 7 ++ .../templates/test_data/lab/sonic_frr.conf | 9 ++ .../templates/test_data/notenants/conf.yaml | 2 + .../test_data/notenants/cumulus_frr.conf | 6 ++ .../test_data/notenants/sonic_frr.conf | 8 ++ .../switcher/templates/tpl/cumulus_frr.tpl | 27 ++++++ .../switcher/templates/tpl/sonic_frr.tpl | 31 +++++++ cmd/internal/switcher/types/conf.go | 43 ++++++++- cmd/internal/switcher/types/types.go | 89 ++++++++++++++---- cmd/internal/switcher/types/types_test.go | 31 +++++++ cmd/internal/vlan/mapping.go | 4 +- cmd/internal/vlan/reservation.go | 4 +- cmd/internal/vlan/reservation_test.go | 3 +- cmd/server.go | 1 + go.mod | 44 ++++----- go.sum | 91 ++++++++++--------- 28 files changed, 416 insertions(+), 128 deletions(-) create mode 100644 cmd/internal/switcher/types/types_test.go diff --git a/Dockerfile b/Dockerfile index 33612ad3..b7f50332 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,10 @@ -FROM golang:1.22-alpine3.20 as builder +FROM golang:1.23-alpine3.20 AS builder WORKDIR /work COPY . . RUN apk add \ make \ binutils \ + coreutils \ git \ gcc \ libpcap-dev \ diff --git a/cmd/config.go b/cmd/config.go index 84bb4864..0fa6c163 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -31,4 +31,5 @@ type Config struct { GrpcClientCertFile string `required:"false" desc:"the gRPC client certificate file" envconfig:"grpc_client_cert_file"` GrpcClientKeyFile string `required:"false" desc:"the gRPC client key file" envconfig:"grpc_client_key_file"` PXEVlanID uint16 `required:"false" default:"4000" desc:"the id of the pxe vlan" envconfig:"pxe_vlan_id"` + AdditionalRouteMapCIDRs []string `required:"false" default:"10.240.0.0/12" desc:"additional route map entries, typically the pod/service CIDRs, one or more CIDR for ipv4 or ipv6, separated by comma" envconfig:"additional_route_map_cidrs"` } diff --git a/cmd/internal/core/core.go b/cmd/internal/core/core.go index 1e77a5f4..56ebd053 100644 --- a/cmd/internal/core/core.go +++ b/cmd/internal/core/core.go @@ -33,7 +33,8 @@ type Core struct { metrics *metrics.Metrics - pxeVlanID uint16 + pxeVlanID uint16 + additionalRouteMapCIDRs []string } type Config struct { @@ -59,7 +60,8 @@ type Config struct { Metrics *metrics.Metrics - PXEVlanID uint16 + PXEVlanID uint16 + AdditionalRouteMapCIDRs []string } func New(c Config) *Core { @@ -82,5 +84,6 @@ func New(c Config) *Core { eventServiceClient: c.EventServiceClient, metrics: c.Metrics, pxeVlanID: c.PXEVlanID, + additionalRouteMapCIDRs: c.AdditionalRouteMapCIDRs, } } diff --git a/cmd/internal/core/reconfigure-switch.go b/cmd/internal/core/reconfigure-switch.go index da1adb1b..f9798756 100644 --- a/cmd/internal/core/reconfigure-switch.go +++ b/cmd/internal/core/reconfigure-switch.go @@ -116,23 +116,22 @@ func (c *Core) reconfigureSwitch(switchName string) (*models.V1SwitchResponse, e func (c *Core) buildSwitcherConfig(s *models.V1SwitchResponse) (*types.Conf, error) { asn64, err := strconv.ParseUint(c.asn, 10, 32) - asn := uint32(asn64) if err != nil { return nil, err } - if c.pxeVlanID >= vlan.VlanIDMin && c.pxeVlanID <= vlan.VlanIDMax { return nil, fmt.Errorf("configured PXE VLAN ID is in the reserved area of %d, %d", vlan.VlanIDMin, vlan.VlanIDMax) } switcherConfig := &types.Conf{ - Name: s.Name, - LogLevel: mapLogLevel(c.logLevel), - ASN: asn, - Loopback: c.loopbackIP, - MetalCoreCIDR: c.cidr, - AdditionalBridgeVIDs: c.additionalBridgeVIDs, - PXEVlanID: c.pxeVlanID, + Name: s.Name, + LogLevel: mapLogLevel(c.logLevel), + ASN: uint32(asn64), // nolint:gosec + Loopback: c.loopbackIP, + MetalCoreCIDR: c.cidr, + AdditionalBridgeVIDs: c.additionalBridgeVIDs, + PXEVlanID: c.pxeVlanID, + AdditionalRouteMapCIDRs: c.additionalRouteMapCIDRs, } p := types.Ports{ @@ -186,7 +185,7 @@ func (c *Core) buildSwitcherConfig(s *models.V1SwitchResponse) (*types.Conf, err if err != nil { return nil, err } - vrf.VNI = uint32(vni64) + vrf.VNI = uint32(vni64) // nolint:gosec vrf.Neighbors = append(vrf.Neighbors, port) if nic.Filter != nil { vrf.Cidrs = nic.Filter.Cidrs @@ -196,7 +195,10 @@ func (c *Core) buildSwitcherConfig(s *models.V1SwitchResponse) (*types.Conf, err switcherConfig.Ports = p c.nos.SanitizeConfig(switcherConfig) - switcherConfig.FillRouteMapsAndIPPrefixLists() + err = switcherConfig.FillRouteMapsAndIPPrefixLists() + if err != nil { + return nil, err + } m, err := vlan.ReadMapping() if err != nil { return nil, err diff --git a/cmd/internal/core/reconfigure-switch_test.go b/cmd/internal/core/reconfigure-switch_test.go index 8a89030e..d2cc8ea8 100644 --- a/cmd/internal/core/reconfigure-switch_test.go +++ b/cmd/internal/core/reconfigure-switch_test.go @@ -12,14 +12,15 @@ import ( func TestBuildSwitcherConfig(t *testing.T) { c := &Core{ - cidr: "10.255.255.2/24", - partitionID: "fra-equ01", - rackID: "rack01", - asn: "420000001", - loopbackIP: "10.0.0.1", - spineUplinks: []string{"swp31", "swp32"}, - additionalBridgeVIDs: []string{"201-256", "301-356"}, - nos: &cumulus.Cumulus{}, + cidr: "10.255.255.2/24", + partitionID: "fra-equ01", + rackID: "rack01", + asn: "420000001", + loopbackIP: "10.0.0.1", + spineUplinks: []string{"swp31", "swp32"}, + additionalBridgeVIDs: []string{"201-256", "301-356"}, + nos: &cumulus.Cumulus{}, + additionalRouteMapCIDRs: []string{"10.240.0.0/12"}, } n1 := "swp1" @@ -53,10 +54,11 @@ func TestBuildSwitcherConfig(t *testing.T) { require.NoError(t, err) require.NotNil(t, actual) expected := &types.Conf{ - LogLevel: "warnings", - Loopback: "10.0.0.1", - MetalCoreCIDR: "10.255.255.2/24", - ASN: 420000001, + LogLevel: "warnings", + Loopback: "10.0.0.1", + MetalCoreCIDR: "10.255.255.2/24", + ASN: 420000001, + AdditionalRouteMapCIDRs: []string{"10.240.0.0/12"}, Ports: types.Ports{ DownPorts: map[string]bool{}, Underlay: []string{"swp31", "swp32"}, @@ -73,8 +75,9 @@ func TestBuildSwitcherConfig(t *testing.T) { Filter: types.Filter{ IPPrefixLists: []types.IPPrefixList{ { - Name: "vrf104001-in-prefixes", - Spec: "permit 10.240.0.0/12 le 32", + AddressFamily: "ip", + Name: "vrf104001-in-prefixes", + Spec: "permit 10.240.0.0/12 le 32", }, }, RouteMaps: []types.RouteMap{ @@ -87,6 +90,7 @@ func TestBuildSwitcherConfig(t *testing.T) { }, }, Cidrs: []string{"10.240.0.0/12"}, + Has4: true, }}, }, AdditionalBridgeVIDs: []string{"201-256", "301-356"}, diff --git a/cmd/internal/switcher/templates/template_test.go b/cmd/internal/switcher/templates/template_test.go index 4bf6b162..924f7a26 100644 --- a/cmd/internal/switcher/templates/template_test.go +++ b/cmd/internal/switcher/templates/template_test.go @@ -8,6 +8,7 @@ import ( "testing" "text/template" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" @@ -39,7 +40,8 @@ func TestCumulusFrrTemplate(t *testing.T) { tt := tests[i] t.Run(tt, func(t *testing.T) { c := readConf(t, path.Join("test_data", tt, "conf.yaml")) - c.FillRouteMapsAndIPPrefixLists() + err := c.FillRouteMapsAndIPPrefixLists() + require.NoError(t, err) tpl := CumulusFrrTemplate("") verifyTemplate(t, tpl, &c, path.Join("test_data", tt, "cumulus_frr.conf")) }) @@ -53,7 +55,8 @@ func TestSonicFrrTpl(t *testing.T) { t.Run(tt, func(t *testing.T) { c := readConf(t, path.Join("test_data", tt, "conf.yaml")) c.CapitalizeVrfName() - c.FillRouteMapsAndIPPrefixLists() + err := c.FillRouteMapsAndIPPrefixLists() + require.NoError(t, err) tpl := SonicFrrTemplate("") verifyTemplate(t, tpl, &c, path.Join("test_data", tt, "sonic_frr.conf")) }) @@ -68,14 +71,16 @@ func TestCustomInterfacesTemplate(t *testing.T) { func TestCustomCumulusFrrTemplate(t *testing.T) { c := readConf(t, "test_data/dev/conf.yaml") - c.FillRouteMapsAndIPPrefixLists() + err := c.FillRouteMapsAndIPPrefixLists() + require.NoError(t, err) tpl := CumulusFrrTemplate("test_data/dev/customtpl/frr.tpl") verifyTemplate(t, tpl, &c, "test_data/dev/customtpl/frr.conf") } func TestCustomSonicFrrTemplate(t *testing.T) { c := readConf(t, "test_data/dev/conf.yaml") - c.FillRouteMapsAndIPPrefixLists() + err := c.FillRouteMapsAndIPPrefixLists() + require.NoError(t, err) tpl := SonicFrrTemplate("test_data/dev/customtpl/frr.tpl") verifyTemplate(t, tpl, &c, "test_data/dev/customtpl/frr.conf") } @@ -83,7 +88,9 @@ func TestCustomSonicFrrTemplate(t *testing.T) { func verifyTemplate(t *testing.T, tpl *template.Template, c *types.Conf, expectedFilename string) { actual := renderToString(t, tpl, c) expected := readExpected(t, expectedFilename) - require.Equal(t, expected, actual, "Wanted: %s\nGot: %s", expected, actual) + if diff := cmp.Diff(expected, actual); diff != "" { + t.Errorf("%s render differs:%s", expectedFilename, diff) + } } func renderToString(t *testing.T, tpl *template.Template, c *types.Conf) string { diff --git a/cmd/internal/switcher/templates/test_data/dev/conf.yaml b/cmd/internal/switcher/templates/test_data/dev/conf.yaml index 39c7eee3..b1f63539 100644 --- a/cmd/internal/switcher/templates/test_data/dev/conf.yaml +++ b/cmd/internal/switcher/templates/test_data/dev/conf.yaml @@ -4,6 +4,9 @@ loglevel: warnings loopback: 10.0.0.10 asn: 4200000010 metalcorecidr: 10.255.255.2/24 +additionalroutemapcidrs: + - "10.240.0.0/12" + - "fd00:10::/64" ports: eth0: addresscidr: 192.168.101.12/24 @@ -36,6 +39,7 @@ ports: cidrs: - "100.127.131.0/24" - "212.17.234.17/32" + - "2001:db8:3::1/128" additionalbridgevids: - 201-256 - 301-356 diff --git a/cmd/internal/switcher/templates/test_data/dev/cumulus_frr.conf b/cmd/internal/switcher/templates/test_data/dev/cumulus_frr.conf index 06ef159d..b3f91296 100644 --- a/cmd/internal/switcher/templates/test_data/dev/cumulus_frr.conf +++ b/cmd/internal/switcher/templates/test_data/dev/cumulus_frr.conf @@ -53,6 +53,13 @@ router bgp 4200000010 neighbor swp3 route-map fw-swp3-in in exit-address-family ! + address-family ipv6 unicast + redistribute connected route-map LOOPBACKS + neighbor FIREWALL allowas-in 2 + neighbor FIREWALL activate + neighbor swp3 route-map fw-swp3-in in + exit-address-family + ! address-family l2vpn evpn advertise-all-vni neighbor FABRIC activate @@ -93,16 +100,28 @@ router bgp 4200000010 vrf vrf104001 neighbor MACHINE route-map vrf104001-in in exit-address-family ! + address-family ipv6 unicast + redistribute connected + neighbor MACHINE maximum-prefix 24000 + neighbor MACHINE activate + neighbor MACHINE route-map vrf104001-in6 in + exit-address-family + ! address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! # route-maps for vrf104001 +ip prefix-list vrf104001-in-prefixes permit 10.240.0.0/12 le 32 ip prefix-list vrf104001-in-prefixes permit 100.127.131.0/24 le 32 ip prefix-list vrf104001-in-prefixes permit 212.17.234.17/32 le 32 -ip prefix-list vrf104001-in-prefixes permit 10.240.0.0/12 le 32 +ip prefix-list vrf104001-in6-prefixes permit 2001:db8:3::1/128 le 128 +ip prefix-list vrf104001-in6-prefixes permit fd00:10::/64 le 128 route-map vrf104001-in permit 10 match ip address prefix-list vrf104001-in-prefixes +route-map vrf104001-in6 permit 10 + match ipv6 address prefix-list vrf104001-in6-prefixes ! line vty ! diff --git a/cmd/internal/switcher/templates/test_data/dev/customtpl/frr.conf b/cmd/internal/switcher/templates/test_data/dev/customtpl/frr.conf index f47d0f09..8253707e 100644 --- a/cmd/internal/switcher/templates/test_data/dev/customtpl/frr.conf +++ b/cmd/internal/switcher/templates/test_data/dev/customtpl/frr.conf @@ -96,14 +96,19 @@ router bgp 4200000010 vrf vrf104001 ! address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! # route-maps for vrf104001 +ip prefix-list vrf104001-in-prefixes permit 10.240.0.0/12 le 32 ip prefix-list vrf104001-in-prefixes permit 100.127.131.0/24 le 32 ip prefix-list vrf104001-in-prefixes permit 212.17.234.17/32 le 32 -ip prefix-list vrf104001-in-prefixes permit 10.240.0.0/12 le 32 +ip prefix-list vrf104001-in6-prefixes permit 2001:db8:3::1/128 le 128 +ip prefix-list vrf104001-in6-prefixes permit fd00:10::/64 le 128 route-map vrf104001-in permit 10 match ip address prefix-list vrf104001-in-prefixes +route-map vrf104001-in6 permit 10 + match ipv6 address prefix-list vrf104001-in6-prefixes ! line vty ! diff --git a/cmd/internal/switcher/templates/test_data/dev/customtpl/frr.tpl b/cmd/internal/switcher/templates/test_data/dev/customtpl/frr.tpl index 6ddcb1c0..264adab1 100644 --- a/cmd/internal/switcher/templates/test_data/dev/customtpl/frr.tpl +++ b/cmd/internal/switcher/templates/test_data/dev/customtpl/frr.tpl @@ -111,6 +111,7 @@ router bgp {{ $ASN }} vrf {{ $vrf }} ! address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! {{- if gt (len $t.IPPrefixLists) 0 }} diff --git a/cmd/internal/switcher/templates/test_data/dev/sonic_frr.conf b/cmd/internal/switcher/templates/test_data/dev/sonic_frr.conf index d0c2b11e..f99832eb 100644 --- a/cmd/internal/switcher/templates/test_data/dev/sonic_frr.conf +++ b/cmd/internal/switcher/templates/test_data/dev/sonic_frr.conf @@ -58,6 +58,15 @@ router bgp 4200000010 neighbor swp3 route-map fw-swp3-in in exit-address-family ! + address-family ipv6 unicast + redistribute connected route-map DENY_MGMT + neighbor FIREWALL allowas-in 2 + # see https://docs.frrouting.org/en/latest/bgp.html#clicmd-neighbor-A.B.C.D-activate + # why activate is required + neighbor FIREWALL activate + neighbor swp3 route-map fw-swp3-in in + exit-address-family + ! address-family l2vpn evpn advertise-all-vni neighbor FABRIC activate @@ -99,16 +108,30 @@ router bgp 4200000010 vrf Vrf104001 neighbor MACHINE route-map Vrf104001-in in exit-address-family ! + address-family ipv6 unicast + redistribute connected + neighbor MACHINE maximum-prefix 24000 + # see https://docs.frrouting.org/en/latest/bgp.html#clicmd-neighbor-A.B.C.D-activate + # why activate is required + neighbor MACHINE activate + neighbor MACHINE route-map Vrf104001-in6 in + exit-address-family + ! address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! # route-maps for Vrf104001 +ip prefix-list Vrf104001-in-prefixes permit 10.240.0.0/12 le 32 ip prefix-list Vrf104001-in-prefixes permit 100.127.131.0/24 le 32 ip prefix-list Vrf104001-in-prefixes permit 212.17.234.17/32 le 32 -ip prefix-list Vrf104001-in-prefixes permit 10.240.0.0/12 le 32 +ip prefix-list Vrf104001-in6-prefixes permit 2001:db8:3::1/128 le 128 +ip prefix-list Vrf104001-in6-prefixes permit fd00:10::/64 le 128 route-map Vrf104001-in permit 10 match ip address prefix-list Vrf104001-in-prefixes +route-map Vrf104001-in6 permit 10 + match ipv6 address prefix-list Vrf104001-in6-prefixes ! line vty ! diff --git a/cmd/internal/switcher/templates/test_data/lab/conf.yaml b/cmd/internal/switcher/templates/test_data/lab/conf.yaml index f6051784..8acf5b11 100644 --- a/cmd/internal/switcher/templates/test_data/lab/conf.yaml +++ b/cmd/internal/switcher/templates/test_data/lab/conf.yaml @@ -4,6 +4,8 @@ loglevel: debugging loopback: 10.0.0.10 asn: 4200000010 metalcorecidr: 10.255.255.2/24 +additionalroutemapcidrs: + - "10.240.0.0/12" ports: eth0: addresscidr: 192.168.0.11 diff --git a/cmd/internal/switcher/templates/test_data/lab/cumulus_frr.conf b/cmd/internal/switcher/templates/test_data/lab/cumulus_frr.conf index 614d7d77..c5b22c6c 100644 --- a/cmd/internal/switcher/templates/test_data/lab/cumulus_frr.conf +++ b/cmd/internal/switcher/templates/test_data/lab/cumulus_frr.conf @@ -53,6 +53,13 @@ router bgp 4200000010 neighbor swp3 route-map fw-swp3-in in exit-address-family ! + address-family ipv6 unicast + redistribute connected route-map LOOPBACKS + neighbor FIREWALL allowas-in 2 + neighbor FIREWALL activate + neighbor swp3 route-map fw-swp3-in in + exit-address-family + ! address-family l2vpn evpn advertise-all-vni neighbor FABRIC activate diff --git a/cmd/internal/switcher/templates/test_data/lab/sonic_frr.conf b/cmd/internal/switcher/templates/test_data/lab/sonic_frr.conf index 2738fe2a..f0c46a87 100644 --- a/cmd/internal/switcher/templates/test_data/lab/sonic_frr.conf +++ b/cmd/internal/switcher/templates/test_data/lab/sonic_frr.conf @@ -58,6 +58,15 @@ router bgp 4200000010 neighbor swp3 route-map fw-swp3-in in exit-address-family ! + address-family ipv6 unicast + redistribute connected route-map DENY_MGMT + neighbor FIREWALL allowas-in 2 + # see https://docs.frrouting.org/en/latest/bgp.html#clicmd-neighbor-A.B.C.D-activate + # why activate is required + neighbor FIREWALL activate + neighbor swp3 route-map fw-swp3-in in + exit-address-family + ! address-family l2vpn evpn advertise-all-vni neighbor FABRIC activate diff --git a/cmd/internal/switcher/templates/test_data/notenants/conf.yaml b/cmd/internal/switcher/templates/test_data/notenants/conf.yaml index a0920ad5..9f0d5795 100644 --- a/cmd/internal/switcher/templates/test_data/notenants/conf.yaml +++ b/cmd/internal/switcher/templates/test_data/notenants/conf.yaml @@ -4,6 +4,8 @@ loglevel: warnings loopback: 10.0.0.10 asn: 4200000010 metalcorecidr: 10.255.255.2/24 +additionalroutemapcidrs: + - "10.240.0.0/12" ports: eth0: addresscidr: 192.168.0.11 diff --git a/cmd/internal/switcher/templates/test_data/notenants/cumulus_frr.conf b/cmd/internal/switcher/templates/test_data/notenants/cumulus_frr.conf index 392a3493..3fa5e941 100644 --- a/cmd/internal/switcher/templates/test_data/notenants/cumulus_frr.conf +++ b/cmd/internal/switcher/templates/test_data/notenants/cumulus_frr.conf @@ -35,6 +35,12 @@ router bgp 4200000010 neighbor FIREWALL allowas-in 2 exit-address-family ! + address-family ipv6 unicast + redistribute connected route-map LOOPBACKS + neighbor FIREWALL allowas-in 2 + neighbor FIREWALL activate + exit-address-family + ! address-family l2vpn evpn advertise-all-vni neighbor FABRIC activate diff --git a/cmd/internal/switcher/templates/test_data/notenants/sonic_frr.conf b/cmd/internal/switcher/templates/test_data/notenants/sonic_frr.conf index e784bf59..fc889b05 100644 --- a/cmd/internal/switcher/templates/test_data/notenants/sonic_frr.conf +++ b/cmd/internal/switcher/templates/test_data/notenants/sonic_frr.conf @@ -40,6 +40,14 @@ router bgp 4200000010 neighbor FIREWALL allowas-in 2 exit-address-family ! + address-family ipv6 unicast + redistribute connected route-map DENY_MGMT + neighbor FIREWALL allowas-in 2 + # see https://docs.frrouting.org/en/latest/bgp.html#clicmd-neighbor-A.B.C.D-activate + # why activate is required + neighbor FIREWALL activate + exit-address-family + ! address-family l2vpn evpn advertise-all-vni neighbor FABRIC activate diff --git a/cmd/internal/switcher/templates/tpl/cumulus_frr.tpl b/cmd/internal/switcher/templates/tpl/cumulus_frr.tpl index 385fa240..4b3e8515 100644 --- a/cmd/internal/switcher/templates/tpl/cumulus_frr.tpl +++ b/cmd/internal/switcher/templates/tpl/cumulus_frr.tpl @@ -60,6 +60,15 @@ router bgp {{ $ASN }} {{- end }} exit-address-family ! + address-family ipv6 unicast + redistribute connected route-map LOOPBACKS + neighbor FIREWALL allowas-in 2 + neighbor FIREWALL activate + {{- range $k, $f := .Ports.Firewalls }} + neighbor {{ $f.Port }} route-map fw-{{ $k }}-in in + {{- end }} + exit-address-family + ! address-family l2vpn evpn advertise-all-vni neighbor FABRIC activate @@ -100,6 +109,7 @@ router bgp {{ $ASN }} vrf {{ $vrf }} neighbor {{ . }} interface peer-group MACHINE {{- end }} ! + {{- if $t.Has4 }} address-family ipv4 unicast redistribute connected neighbor MACHINE maximum-prefix 24000 @@ -108,8 +118,25 @@ router bgp {{ $ASN }} vrf {{ $vrf }} {{- end }} exit-address-family ! + {{- end }} + {{- if $t.Has6 }} + address-family ipv6 unicast + redistribute connected + neighbor MACHINE maximum-prefix 24000 + neighbor MACHINE activate + {{- if gt (len $t.IPPrefixLists) 0 }} + neighbor MACHINE route-map {{ $vrf }}-in6 in + {{- end }} + exit-address-family + ! + {{- end }} address-family l2vpn evpn + {{- if $t.Has4 }} advertise ipv4 unicast + {{- end }} + {{- if $t.Has6 }} + advertise ipv6 unicast + {{- end }} exit-address-family ! {{- if gt (len $t.IPPrefixLists) 0 }} diff --git a/cmd/internal/switcher/templates/tpl/sonic_frr.tpl b/cmd/internal/switcher/templates/tpl/sonic_frr.tpl index 2d81bdb5..1d2d96fa 100644 --- a/cmd/internal/switcher/templates/tpl/sonic_frr.tpl +++ b/cmd/internal/switcher/templates/tpl/sonic_frr.tpl @@ -65,6 +65,17 @@ router bgp {{ $ASN }} {{- end }} exit-address-family ! + address-family ipv6 unicast + redistribute connected route-map DENY_MGMT + neighbor FIREWALL allowas-in 2 + # see https://docs.frrouting.org/en/latest/bgp.html#clicmd-neighbor-A.B.C.D-activate + # why activate is required + neighbor FIREWALL activate + {{- range $k, $f := .Ports.Firewalls }} + neighbor {{ $f.Port }} route-map fw-{{ $k }}-in in + {{- end }} + exit-address-family + ! address-family l2vpn evpn advertise-all-vni neighbor FABRIC activate @@ -108,6 +119,7 @@ router bgp {{ $ASN }} vrf {{ $vrf }} neighbor {{ . }} interface peer-group MACHINE {{- end }} ! + {{- if $t.Has4 }} address-family ipv4 unicast redistribute connected neighbor MACHINE maximum-prefix 24000 @@ -116,8 +128,27 @@ router bgp {{ $ASN }} vrf {{ $vrf }} {{- end }} exit-address-family ! + {{- end }} + {{- if $t.Has6 }} + address-family ipv6 unicast + redistribute connected + neighbor MACHINE maximum-prefix 24000 + # see https://docs.frrouting.org/en/latest/bgp.html#clicmd-neighbor-A.B.C.D-activate + # why activate is required + neighbor MACHINE activate + {{- if gt (len $t.IPPrefixLists) 0 }} + neighbor MACHINE route-map {{ $vrf }}-in6 in + {{- end }} + exit-address-family + ! + {{- end }} address-family l2vpn evpn + {{- if $t.Has4 }} advertise ipv4 unicast + {{- end }} + {{- if $t.Has6 }} + advertise ipv6 unicast + {{- end }} exit-address-family ! {{- if gt (len $t.IPPrefixLists) 0 }} diff --git a/cmd/internal/switcher/types/conf.go b/cmd/internal/switcher/types/conf.go index 94193207..8daf5d9f 100644 --- a/cmd/internal/switcher/types/conf.go +++ b/cmd/internal/switcher/types/conf.go @@ -1,7 +1,11 @@ package types import ( + "fmt" + "net/netip" + "github.com/metal-stack/metal-core/cmd/internal/vlan" + "go4.org/netipx" "golang.org/x/text/cases" "golang.org/x/text/language" ) @@ -29,15 +33,48 @@ outer_loop: return nil } -func (c *Conf) FillRouteMapsAndIPPrefixLists() { +func (c *Conf) FillRouteMapsAndIPPrefixLists() error { for port, f := range c.Ports.Firewalls { f.Assemble("fw-"+port, f.Vnis, f.Cidrs) } for vrf, t := range c.Ports.Vrfs { - podCidr := "10.240.0.0/12" - t.Cidrs = append(t.Cidrs, podCidr) + t.Cidrs = append(t.Cidrs, c.AdditionalRouteMapCIDRs...) + + var err error + t.Cidrs, err = compactCidrs(t.Cidrs) + if err != nil { + return err + } + + cidrsByAf := cidrsByAddressfamily(t.Cidrs) + t.Has4 = len(cidrsByAf.ipv4Cidrs) > 0 + t.Has6 = len(cidrsByAf.ipv6Cidrs) > 0 t.Assemble(vrf, []string{}, t.Cidrs) } + return nil +} +func compactCidrs(cidrs []string) ([]string, error) { + var ( + compacted []string + ipsetBuilder netipx.IPSetBuilder + ) + + for _, cidr := range cidrs { + parsed, err := netip.ParsePrefix(cidr) + if err != nil { + return nil, err + } + ipsetBuilder.AddPrefix(parsed) + } + set, err := ipsetBuilder.IPSet() + if err != nil { + return nil, fmt.Errorf("unable to create ipset:%w", err) + } + for _, pfx := range set.Prefixes() { + compacted = append(compacted, pfx.String()) + } + + return compacted, nil } // CapitalizeVrfName capitalizes VRF names, which is requirement for SONiC diff --git a/cmd/internal/switcher/types/types.go b/cmd/internal/switcher/types/types.go index 06795780..c5a7f80d 100644 --- a/cmd/internal/switcher/types/types.go +++ b/cmd/internal/switcher/types/types.go @@ -2,18 +2,20 @@ package types import ( "fmt" + "net/netip" ) // Conf holds the switch configuration type Conf struct { - Name string - LogLevel string - Loopback string - ASN uint32 - Ports Ports - MetalCoreCIDR string - AdditionalBridgeVIDs []string - PXEVlanID uint16 + Name string + LogLevel string + Loopback string + ASN uint32 + Ports Ports + MetalCoreCIDR string + AdditionalBridgeVIDs []string + PXEVlanID uint16 + AdditionalRouteMapCIDRs []string } type Ports struct { @@ -33,6 +35,8 @@ type Vrf struct { VLANID uint16 Neighbors []string Cidrs []string + Has4 bool + Has6 bool } type Firewall struct { @@ -63,12 +67,14 @@ type RouteMap struct { // IPPrefixList represents 'ip prefix-list' filtering mechanism to be used in combination with route-maps. type IPPrefixList struct { - Name string - Spec string + AddressFamily string + Name string + Spec string } func (s *Filter) Assemble(rmPrefix string, vnis, cidrs []string) { - if len(cidrs) > 0 { + cidrsByAf := cidrsByAddressfamily(cidrs) + if len(cidrsByAf.ipv4Cidrs) > 0 { prefixRouteMapName := fmt.Sprintf("%s-in", rmPrefix) prefixListName := fmt.Sprintf("%s-in-prefixes", rmPrefix) rm := RouteMap{ @@ -78,15 +84,19 @@ func (s *Filter) Assemble(rmPrefix string, vnis, cidrs []string) { Order: 10, } s.RouteMaps = append(s.RouteMaps, rm) - - for _, cidr := range cidrs { - spec := fmt.Sprintf("permit %s le 32", cidr) - prefixList := IPPrefixList{ - Name: prefixListName, - Spec: spec, - } - s.IPPrefixLists = append(s.IPPrefixLists, prefixList) + s.addPrefixList(prefixListName, cidrsByAf.ipv4Cidrs, "ip") + } + if len(cidrsByAf.ipv6Cidrs) > 0 { + prefixRouteMapName := fmt.Sprintf("%s-in6", rmPrefix) + prefixListName := fmt.Sprintf("%s-in6-prefixes", rmPrefix) + rm := RouteMap{ + Name: prefixRouteMapName, + Entries: []string{fmt.Sprintf("match ipv6 address prefix-list %s", prefixListName)}, + Policy: "permit", + Order: 10, } + s.RouteMaps = append(s.RouteMaps, rm) + s.addPrefixList(prefixListName, cidrsByAf.ipv6Cidrs, "ipv6") } if len(vnis) > 0 { vniRouteMapName := fmt.Sprintf("%s-vni", rmPrefix) @@ -101,3 +111,44 @@ func (s *Filter) Assemble(rmPrefix string, vnis, cidrs []string) { } } } + +func (s *Filter) addPrefixList(prefixListName string, cidrs []string, af string) { + for _, cidr := range cidrs { + prefix, err := netip.ParsePrefix(cidr) + if err != nil { + continue + } + spec := fmt.Sprintf("permit %s le %d", cidr, prefix.Addr().BitLen()) + prefixList := IPPrefixList{ + AddressFamily: af, + Name: prefixListName, + Spec: spec, + } + s.IPPrefixLists = append(s.IPPrefixLists, prefixList) + } +} + +type cidrsByAf struct { + ipv4Cidrs []string + ipv6Cidrs []string +} + +func cidrsByAddressfamily(cidrs []string) cidrsByAf { + cs := cidrsByAf{ + ipv4Cidrs: []string{}, + ipv6Cidrs: []string{}, + } + for _, cidr := range cidrs { + prefix, err := netip.ParsePrefix(cidr) + if err != nil { + continue + } + if prefix.Addr().Is4() { + cs.ipv4Cidrs = append(cs.ipv4Cidrs, cidr) + } + if prefix.Addr().Is6() { + cs.ipv6Cidrs = append(cs.ipv6Cidrs, cidr) + } + } + return cs +} diff --git a/cmd/internal/switcher/types/types_test.go b/cmd/internal/switcher/types/types_test.go new file mode 100644 index 00000000..979b930a --- /dev/null +++ b/cmd/internal/switcher/types/types_test.go @@ -0,0 +1,31 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_cidrsByAddressfamily(t *testing.T) { + tests := []struct { + name string + cidrs []string + want cidrsByAf + }{ + { + name: "simple", + cidrs: []string{"10.0.0.0/8", "2001:db8:7::/48", "192.168.178.0/24", "2001:db8:2::/48"}, + want: cidrsByAf{ + ipv4Cidrs: []string{"10.0.0.0/8", "192.168.178.0/24"}, + ipv6Cidrs: []string{"2001:db8:7::/48", "2001:db8:2::/48"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := cidrsByAddressfamily(tt.cidrs) + require.ElementsMatch(t, got.ipv4Cidrs, tt.want.ipv4Cidrs) + require.ElementsMatch(t, got.ipv6Cidrs, tt.want.ipv6Cidrs) + }) + } +} diff --git a/cmd/internal/vlan/mapping.go b/cmd/internal/vlan/mapping.go index 47711132..b6e10e16 100644 --- a/cmd/internal/vlan/mapping.go +++ b/cmd/internal/vlan/mapping.go @@ -23,12 +23,12 @@ func ReadMapping() (Mapping, error) { if nic.Type() == "vxlan" { vx := nic.(*netlink.Vxlan) vni := vx.VxlanId - ifindex := int32(nic.Attrs().Index) + ifindex := int32(nic.Attrs().Index) // nolint:gosec if len(bvl[ifindex]) < 1 { return nil, fmt.Errorf("no vlan mapping could be determined for vxlan interface %s", nic.Attrs().Name) } vlan := bvl[ifindex][0].Vid - m[vlan] = uint32(vni) + m[vlan] = uint32(vni) // nolint:gosec } } return m, nil diff --git a/cmd/internal/vlan/reservation.go b/cmd/internal/vlan/reservation.go index ec317cd9..6adc500c 100644 --- a/cmd/internal/vlan/reservation.go +++ b/cmd/internal/vlan/reservation.go @@ -17,13 +17,13 @@ func (m Mapping) ReserveVlanIDs(n uint16) ([]uint16, error) { func (m Mapping) reserveVlanIDs(min, max, n uint16) ([]uint16, error) { maxVlans := max - min + 1 - if uint16(len(m))+n > maxVlans { + if len(m)+int(n) > int(maxVlans) { return nil, fmt.Errorf("can not reserve %d vlan ids, %d are already taken and %d possible at max", n, len(m), maxVlans) } // scan vlan id range for n free vlan ids r := []uint16{} for i := min; i <= max; i++ { - if uint16(len(r)) >= n { + if len(r) >= int(n) { break } if _, has := m[i]; !has { diff --git a/cmd/internal/vlan/reservation_test.go b/cmd/internal/vlan/reservation_test.go index 0771a6dd..e86b0e80 100644 --- a/cmd/internal/vlan/reservation_test.go +++ b/cmd/internal/vlan/reservation_test.go @@ -1,7 +1,6 @@ package vlan import ( - "fmt" "testing" "github.com/stretchr/testify/assert" @@ -53,7 +52,7 @@ func TestReserveVlanIDs(t *testing.T) { m[t] = uint32(t) } a, _ := m.reserveVlanIDs(tt.input.min, tt.input.max, tt.input.n) - assert.Equal(t, tt.expected, a, fmt.Sprintf("reservation differs (taken: %v)", tt.input.taken)) + assert.Equal(t, tt.expected, a, "reservation differs (taken: %v)", tt.input.taken) }) } } diff --git a/cmd/server.go b/cmd/server.go index 6b6aec90..dd49755a 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -102,6 +102,7 @@ func Run() { EventServiceClient: grpcClient.NewEventClient(), Metrics: metrics, PXEVlanID: cfg.PXEVlanID, + AdditionalRouteMapCIDRs: cfg.AdditionalRouteMapCIDRs, }) err = c.RegisterSwitch() diff --git a/go.mod b/go.mod index 0c7723c7..9609020a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/metal-stack/metal-core -go 1.22 +go 1.23 require ( github.com/avast/retry-go/v4 v4.6.0 @@ -9,15 +9,16 @@ require ( github.com/google/go-cmp v0.6.0 github.com/kelseyhightower/envconfig v1.4.0 github.com/metal-stack/go-lldpd v0.4.7 - github.com/metal-stack/metal-api v0.32.3 - github.com/metal-stack/metal-go v0.32.3 + github.com/metal-stack/metal-api v0.34.0 + github.com/metal-stack/metal-go v0.34.0 github.com/metal-stack/v v1.0.3 - github.com/prometheus/client_golang v1.19.1 + github.com/prometheus/client_golang v1.20.2 github.com/redis/go-redis/v9 v9.6.1 github.com/stretchr/testify v1.9.0 - github.com/vishvananda/netlink v1.2.1-beta.2 - golang.org/x/text v0.16.0 - google.golang.org/grpc v1.65.0 + github.com/vishvananda/netlink v1.3.0 + go4.org/netipx v0.0.0-20231129151722-fdeea329fbba + golang.org/x/text v0.18.0 + google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 ) @@ -30,7 +31,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/go-jose/go-jose/v4 v4.0.3 // indirect + github.com/go-jose/go-jose/v4 v4.0.4 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.23.0 // indirect @@ -50,16 +51,17 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/lestrrat-go/blackmagic v1.0.2 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc v1.0.6 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect - github.com/lestrrat-go/jwx/v2 v2.1.0 // indirect + github.com/lestrrat-go/jwx/v2 v2.1.1 // indirect github.com/lestrrat-go/option v1.0.1 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 // indirect github.com/mdlayher/lldp v0.0.0-20150915211757-afd9f83164c5 // indirect - github.com/metal-stack/metal-lib v0.17.2 // indirect + github.com/metal-stack/metal-lib v0.18.1 // indirect github.com/metal-stack/security v0.8.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -67,18 +69,18 @@ require ( github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.58.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/vishvananda/netns v0.0.4 // indirect - go.mongodb.org/mongo-driver v1.16.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - golang.org/x/crypto v0.25.0 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f // indirect + go.mongodb.org/mongo-driver v1.16.1 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect ) diff --git a/go.sum b/go.sum index 6a8db983..dbf0b16f 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtz github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/go-jose/go-jose/v4 v4.0.3 h1:o8aphO8Hv6RPmH+GfzVuyf7YXSBibp+8YyHdOoDESGo= -github.com/go-jose/go-jose/v4 v4.0.3/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -76,10 +76,14 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= @@ -88,8 +92,8 @@ github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCG github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx/v2 v2.1.0 h1:0zs7Ya6+39qoit7gwAf+cYm1zzgS3fceIdo7RmQ5lkw= -github.com/lestrrat-go/jwx/v2 v2.1.0/go.mod h1:Xpw9QIaUGiIUD1Wx0NcY1sIHwFf8lDuZn/cmxtXYRys= +github.com/lestrrat-go/jwx/v2 v2.1.1 h1:Y2ltVl8J6izLYFs54BVcpXLv5msSW4o8eXwnzZLI32E= +github.com/lestrrat-go/jwx/v2 v2.1.1/go.mod h1:4LvZg7oxu6Q5VJwn7Mk/UwooNRnTHUpXBj2C4j3HNx0= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -102,12 +106,12 @@ github.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jm github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= github.com/metal-stack/go-lldpd v0.4.7 h1:Y3FALidODscleqJCS6sGgBunxyLX1scNT7cMoKn6b1Q= github.com/metal-stack/go-lldpd v0.4.7/go.mod h1:CYKuwnjSZ6zYmAMKLy45/QAQJKj5xZnkfv2zyi+B33o= -github.com/metal-stack/metal-api v0.32.3 h1:ImJhWEHZYGBCIeZ0tW6UW5Xz0YfaEZVLXYHCvQ7Lbto= -github.com/metal-stack/metal-api v0.32.3/go.mod h1:aX7G+aUWmSsi5Af/c6PgN1osD6yuVU+QmOdlMRu7KkA= -github.com/metal-stack/metal-go v0.32.3 h1:rM+Re3iLVuGN9GOQzV4HKodUmlhuimdbCaXbaCBfVy4= -github.com/metal-stack/metal-go v0.32.3/go.mod h1:3MJTYCS4YJz8D8oteTKhjpaAKNMMjMKYDrIy9awHGtQ= -github.com/metal-stack/metal-lib v0.17.2 h1:T1rxCPgagHW/M0wWSrOj4hWsPZMSt1pYw90Z3vBm88Q= -github.com/metal-stack/metal-lib v0.17.2/go.mod h1:nyNGI4DZFOcWbSoq2Y6V3SHpFxuXBIqYBZHTb6cy//s= +github.com/metal-stack/metal-api v0.34.0 h1:/FZ14svO43D0OMoo3JfiupdBwaOwjUZcHl4qeoe4z4g= +github.com/metal-stack/metal-api v0.34.0/go.mod h1:6ayMjTemhyua2nD/RWsxKxkd9zBY1fRxxGGG9/OlGlU= +github.com/metal-stack/metal-go v0.34.0 h1:X4Wlt2OAhsu3Lq+rHSWnWeASmX6CYvOxnL6DxmjnzbU= +github.com/metal-stack/metal-go v0.34.0/go.mod h1:3MJTYCS4YJz8D8oteTKhjpaAKNMMjMKYDrIy9awHGtQ= +github.com/metal-stack/metal-lib v0.18.1 h1:Kjmf/Z/6pWemR8O6ttbNPQ9PjeT3ON60sBNu51Lgi1M= +github.com/metal-stack/metal-lib v0.18.1/go.mod h1:GJjipRpHmpd2vjBtsaw9gGk5ZFan7NlShyjIsTdY1x4= github.com/metal-stack/security v0.8.1 h1:4zmVUxZvDWShVvVIxM3XhIv7pTmPe9DvACRIHW6YTsk= github.com/metal-stack/security v0.8.1/go.mod h1:OO8ZilZO6fUV5QEmwc7HP/RAjqYrGQxXoYIddJ9TvqE= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= @@ -129,12 +133,12 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= +github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.58.0 h1:N+N8vY4/23r6iYfD3UQZUoJPnUYAo7v6LG5XZxjZTXo= +github.com/prometheus/common v0.58.0/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= @@ -149,58 +153,59 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= -github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk= +github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= -go.mongodb.org/mongo-driver v1.16.0 h1:tpRsfBJMROVHKpdGyc1BBEzzjDUWjItxbVSZ8Ls4BQ4= -go.mongodb.org/mongo-driver v1.16.0/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= +go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f h1:RARaIm8pxYuxyNPbBQf5igT7XdOyCNtat1qAT2ZxjU4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240725223205-93522f1f2a9f/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=