Skip to content

Commit fe9c17c

Browse files
authored
Compact BGPFilter to save switch memory (#559)
1 parent 7a5f643 commit fe9c17c

File tree

3 files changed

+126
-2
lines changed

3 files changed

+126
-2
lines changed

cmd/metal-api/internal/service/switch-service.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/avast/retry-go/v4"
1515
restfulspec "github.com/emicklei/go-restful-openapi/v2"
1616
restful "github.com/emicklei/go-restful/v3"
17+
"go4.org/netipx"
1718

1819
"github.com/metal-stack/metal-api/cmd/metal-api/internal/datastore"
1920
"github.com/metal-stack/metal-api/cmd/metal-api/internal/metal"
@@ -835,6 +836,9 @@ func makeBGPFilterMachine(m metal.Machine, ips metal.IPsMap) (v1.BGPFilter, erro
835836
if underlay != nil && underlay.ContainsIP(i.IPAddress) {
836837
continue
837838
}
839+
840+
// TODO machine BGPFilter must not contain firewall private network IPs
841+
838842
// Allow all other ip addresses allocated for the project.
839843
ipwithMask, err := ipWithMask(i.IPAddress)
840844
if err != nil {
@@ -843,7 +847,11 @@ func makeBGPFilterMachine(m metal.Machine, ips metal.IPsMap) (v1.BGPFilter, erro
843847
cidrs = append(cidrs, ipwithMask)
844848
}
845849

846-
return v1.NewBGPFilter(vnis, cidrs), nil
850+
compactedCidrs, err := compactCidrs(cidrs)
851+
if err != nil {
852+
return v1.BGPFilter{}, err
853+
}
854+
return v1.NewBGPFilter(vnis, compactedCidrs), nil
847855
}
848856

849857
func ipWithMask(ip string) (string, error) {
@@ -854,6 +862,28 @@ func ipWithMask(ip string) (string, error) {
854862
return fmt.Sprintf("%s/%d", ip, parsed.BitLen()), nil
855863
}
856864

865+
func compactCidrs(cidrs []string) ([]string, error) {
866+
// compact all cidrs which are used to be added to the route map
867+
// to find the smallest sorted set of prefixes which covers all cidrs which need to be added.
868+
var ipsetBuilder netipx.IPSetBuilder
869+
for _, cidr := range cidrs {
870+
parsed, err := netip.ParsePrefix(cidr)
871+
if err != nil {
872+
return nil, err
873+
}
874+
ipsetBuilder.AddPrefix(parsed)
875+
}
876+
set, err := ipsetBuilder.IPSet()
877+
if err != nil {
878+
return nil, fmt.Errorf("unable to create ipset:%w", err)
879+
}
880+
var compactedCidrs []string
881+
for _, pfx := range set.Prefixes() {
882+
compactedCidrs = append(compactedCidrs, pfx.String())
883+
}
884+
return compactedCidrs, nil
885+
}
886+
857887
func makeBGPFilter(m metal.Machine, vrf string, ips metal.IPsMap) (v1.BGPFilter, error) {
858888
var (
859889
filter v1.BGPFilter

cmd/metal-api/internal/service/switch-service_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,3 +1561,97 @@ func Test_SwitchDelete(t *testing.T) {
15611561
})
15621562
}
15631563
}
1564+
1565+
func TestCompactCidrs(t *testing.T) {
1566+
// sample cidrs from a production cluster passed in to be added to the route map
1567+
cidrs := []string{
1568+
"10.4.0.31/32",
1569+
"10.6.0.25/32",
1570+
"10.64.28.0/22",
1571+
"10.67.36.138/32",
1572+
"10.76.20.12/32",
1573+
"10.76.20.14/32",
1574+
"10.76.20.15/32",
1575+
"10.76.20.16/32",
1576+
"10.76.20.17/32",
1577+
"10.76.20.2/32",
1578+
"10.76.20.3/32",
1579+
"10.76.20.4/32",
1580+
"10.76.20.5/32",
1581+
"10.76.20.6/32",
1582+
"10.76.20.7/32",
1583+
"10.76.20.8/32",
1584+
"10.76.20.9/32",
1585+
"10.78.248.134/32",
1586+
"2001:db8::7/128",
1587+
"2001:db8::8/128",
1588+
"2001:db8::20/128",
1589+
"2001:db8::db/128",
1590+
"100.127.130.178/32",
1591+
"100.127.130.179/32",
1592+
"100.127.130.180/32",
1593+
"100.127.130.181/32",
1594+
"100.127.130.182/32",
1595+
"100.127.130.183/32",
1596+
"100.153.67.112/32",
1597+
"100.153.67.113/32",
1598+
"100.153.67.114/32",
1599+
"100.153.67.115/32",
1600+
"100.153.67.116/32",
1601+
"100.34.85.136/32",
1602+
"100.34.85.17/32",
1603+
"100.34.89.209/32",
1604+
"2001:db8::9/128",
1605+
"2001:db8::10/128",
1606+
"100.34.89.210/32",
1607+
"100.90.30.12/32",
1608+
"100.90.30.13/32",
1609+
"100.90.30.14/32",
1610+
"100.90.30.15/32",
1611+
"100.90.30.16/32",
1612+
"100.90.30.32/32",
1613+
"100.90.30.4/32",
1614+
"100.90.30.7/32",
1615+
}
1616+
1617+
compactedCidrs := []string{
1618+
"10.4.0.31/32",
1619+
"10.6.0.25/32",
1620+
"10.64.28.0/22",
1621+
"10.67.36.138/32",
1622+
"10.76.20.2/31",
1623+
"10.76.20.4/30",
1624+
"10.76.20.8/31",
1625+
"10.76.20.12/32",
1626+
"10.76.20.14/31",
1627+
"10.76.20.16/31",
1628+
"10.78.248.134/32",
1629+
"100.90.30.4/32",
1630+
"100.90.30.7/32",
1631+
"100.90.30.12/30",
1632+
"100.90.30.16/32",
1633+
"100.90.30.32/32",
1634+
"100.127.130.178/31",
1635+
"100.127.130.180/30",
1636+
"100.153.67.112/30",
1637+
"100.153.67.116/32",
1638+
"100.34.85.17/32",
1639+
"100.34.85.136/32",
1640+
"100.34.89.209/32",
1641+
"100.34.89.210/32",
1642+
"2001:db8::7/128",
1643+
"2001:db8::8/127",
1644+
"2001:db8::10/128",
1645+
"2001:db8::20/128",
1646+
"2001:db8::db/128",
1647+
}
1648+
1649+
compacted, err := compactCidrs(cidrs)
1650+
require.NoError(t, err)
1651+
require.Less(t, len(compacted), len(cidrs))
1652+
require.Len(t, compacted, 29)
1653+
1654+
t.Logf("aggregated cidrs:%s old count:%d new count:%d", compacted, len(cidrs), len(compacted))
1655+
1656+
require.ElementsMatch(t, compactedCidrs, compacted)
1657+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ require (
3030
github.com/spf13/viper v1.19.0
3131
github.com/stretchr/testify v1.9.0
3232
github.com/testcontainers/testcontainers-go v0.32.0
33+
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
3334
golang.org/x/crypto v0.26.0
3435
golang.org/x/sync v0.8.0
3536
google.golang.org/grpc v1.65.0
@@ -199,7 +200,6 @@ require (
199200
go.uber.org/multierr v1.11.0 // indirect
200201
go.uber.org/zap v1.27.0 // indirect
201202
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
202-
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
203203
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
204204
golang.org/x/net v0.28.0 // indirect
205205
golang.org/x/oauth2 v0.22.0 // indirect

0 commit comments

Comments
 (0)