Skip to content

Commit

Permalink
fix: populate routes to BGP neighbors (Equinix Metal)
Browse files Browse the repository at this point in the history
Fixes #8267

Also refactor the code so that we don't fail hard on mutiple bonds, but
it's not clear still how to attach addresses, as they don't have a
interface name field, so for now attaching to the first bond.

Fixes #8411

Signed-off-by: Andrey Smirnov <[email protected]>
  • Loading branch information
smira committed Mar 21, 2024
1 parent 19f15a8 commit f737e64
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"bytes"
"context"
"encoding/json"
stderrors "errors"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -71,6 +70,12 @@ type Address struct {
Gateway string `json:"gateway"`
}

// BGPNeighbor holds BGP neighbor info from the equinixmetal metadata.
type BGPNeighbor struct {
AddressFamily int `json:"address_family"`
PeerIPs []string `json:"peer_ips"`
}

const (
// EquinixMetalUserDataEndpoint is the local metadata endpoint for Equinix.
EquinixMetalUserDataEndpoint = "https://metadata.platformequinix.com/userdata"
Expand Down Expand Up @@ -122,27 +127,23 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
// translate the int returned from bond mode metadata to the type needed by network resources
bondMode := nethelpers.BondMode(uint8(equinixMetadata.Network.Bonding.Mode))

// determine bond name and build list of interfaces enslaved by the bond
bondName := ""

hostInterfaces, err := safe.StateListAll[*network.LinkStatus](ctx, st)
if err != nil {
return nil, fmt.Errorf("error listing host interfaces: %w", err)
}

slaveIndex := 0
bondSlaveIndexes := map[string]int{}
firstBond := ""

for _, iface := range equinixMetadata.Network.Interfaces {
if iface.Bond == "" {
continue
}

if bondName != "" && iface.Bond != bondName {
return nil, stderrors.New("encountered multiple bonds. this is unexpected in the equinix metal platform")
if firstBond == "" {
firstBond = iface.Bond
}

bondName = iface.Bond

found := false

hostInterfaceIter := hostInterfaces.Iterator()
Expand All @@ -154,17 +155,20 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
if hostInterfaceIter.Value().TypedSpec().PermanentAddr.String() == iface.MAC {
found = true

slaveIndex := bondSlaveIndexes[iface.Bond]

networkConfig.Links = append(networkConfig.Links,
network.LinkSpecSpec{
Name: hostInterfaceIter.Value().Metadata().ID(),
Up: true,
BondSlave: network.BondSlave{
MasterName: bondName,
MasterName: iface.Bond,
SlaveIndex: slaveIndex,
},
ConfigLayer: network.ConfigPlatform,
})
slaveIndex++

bondSlaveIndexes[iface.Bond]++

break
}
Expand All @@ -173,39 +177,44 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
if !found {
log.Printf("interface with MAC %q wasn't found on the host, adding with the name from metadata", iface.MAC)

slaveIndex := bondSlaveIndexes[iface.Bond]

networkConfig.Links = append(networkConfig.Links,
network.LinkSpecSpec{
ConfigLayer: network.ConfigPlatform,
Name: iface.Name,
Up: true,
BondSlave: network.BondSlave{
MasterName: bondName,
MasterName: iface.Bond,
SlaveIndex: slaveIndex,
},
})
slaveIndex++

bondSlaveIndexes[iface.Bond]++
}
}

bondLink := network.LinkSpecSpec{
ConfigLayer: network.ConfigPlatform,
Name: bondName,
Logical: true,
Up: true,
Kind: network.LinkKindBond,
Type: nethelpers.LinkEther,
BondMaster: network.BondMasterSpec{
Mode: bondMode,
DownDelay: 200,
MIIMon: 100,
UpDelay: 200,
HashPolicy: nethelpers.BondXmitPolicyLayer34,
},
}
for bondName := range bondSlaveIndexes {
bondLink := network.LinkSpecSpec{
ConfigLayer: network.ConfigPlatform,
Name: bondName,
Logical: true,
Up: true,
Kind: network.LinkKindBond,
Type: nethelpers.LinkEther,
BondMaster: network.BondMasterSpec{
Mode: bondMode,
DownDelay: 200,
MIIMon: 100,
UpDelay: 200,
HashPolicy: nethelpers.BondXmitPolicyLayer34,
},
}

networkadapter.BondMasterSpec(&bondLink.BondMaster).FillDefaults()
networkadapter.BondMasterSpec(&bondLink.BondMaster).FillDefaults()

networkConfig.Links = append(networkConfig.Links, bondLink)
networkConfig.Links = append(networkConfig.Links, bondLink)
}

// 2. addresses

Expand Down Expand Up @@ -233,7 +242,7 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
networkConfig.Addresses = append(networkConfig.Addresses,
network.AddressSpecSpec{
ConfigLayer: network.ConfigPlatform,
LinkName: bondName,
LinkName: firstBond,
Address: ipAddr,
Scope: nethelpers.ScopeGlobal,
Flags: nethelpers.AddressFlags(nethelpers.AddressPermanent),
Expand All @@ -249,6 +258,7 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
}

// 3. routes
var privateGateway netip.Addr

for _, addr := range equinixMetadata.Network.Addresses {
if !(addr.Enabled && addr.Management) {
Expand All @@ -275,7 +285,7 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
route := network.RouteSpecSpec{
ConfigLayer: network.ConfigPlatform,
Gateway: gw,
OutLinkName: bondName,
OutLinkName: firstBond,
Table: nethelpers.TableMain,
Protocol: nethelpers.ProtocolStatic,
Type: nethelpers.TypeUnicast,
Expand All @@ -298,6 +308,8 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
return nil, err
}

privateGateway = gw

dest, err := netip.ParsePrefix(privSubnet)
if err != nil {
return nil, err
Expand All @@ -307,7 +319,7 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
ConfigLayer: network.ConfigPlatform,
Gateway: gw,
Destination: dest,
OutLinkName: bondName,
OutLinkName: firstBond,
Table: nethelpers.TableMain,
Protocol: nethelpers.ProtocolStatic,
Type: nethelpers.TypeUnicast,
Expand Down Expand Up @@ -347,6 +359,36 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
ProviderID: fmt.Sprintf("equinixmetal://%s", equinixMetadata.ID),
}

// 6. BGP neighbors

for _, bgpNeighbor := range equinixMetadata.BGPNeighbors {
if bgpNeighbor.AddressFamily != 4 {
continue
}

for _, peerIP := range bgpNeighbor.PeerIPs {
peer, err := netip.ParseAddr(peerIP)
if err != nil {
return nil, err
}

route := network.RouteSpecSpec{
ConfigLayer: network.ConfigPlatform,
Gateway: privateGateway,
Destination: netip.PrefixFrom(peer, 32),
OutLinkName: firstBond,
Table: nethelpers.TableMain,
Protocol: nethelpers.ProtocolStatic,
Type: nethelpers.TypeUnicast,
Family: nethelpers.FamilyInet4,
}

route.Normalize()

networkConfig.Routes = append(networkConfig.Routes, route)
}
}

return networkConfig, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ package equinixmetal

// MetadataConfig holds equinixmetal metadata info.
type MetadataConfig struct {
ID string `json:"id"`
Hostname string `json:"hostname"`
Plan string `json:"plan"`
Metro string `json:"metro"`
Facility string `json:"facility"`
Network Network `json:"network"`
PrivateSubnets []string `json:"private_subnets"`
ID string `json:"id"`
Hostname string `json:"hostname"`
Plan string `json:"plan"`
Metro string `json:"metro"`
Facility string `json:"facility"`
Network Network `json:"network"`
BGPNeighbors []BGPNeighbor `json:"bgp_neighbors"`
PrivateSubnets []string `json:"private_subnets"`
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,28 @@ routes:
flags: ""
protocol: static
layer: platform
- family: inet4
dst: 169.254.255.1/32
src: ""
gateway: 10.66.142.16
outLinkName: bond0
table: main
scope: global
type: unicast
flags: ""
protocol: static
layer: platform
- family: inet4
dst: 169.254.255.2/32
src: ""
gateway: 10.66.142.16
outLinkName: bond0
table: main
scope: global
type: unicast
flags: ""
protocol: static
layer: platform
hostnames:
- hostname: infra-green-ci
domainname: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,38 @@
],
"metal_gateways": []
},
"bgp_neighbors": [
{
"address_family": 4,
"customer_as": 65000,
"customer_ip": "10.67.50.1",
"md5_enabled": false,
"md5_password": null,
"multihop": true,
"peer_as": 65530,
"peer_ips": [
"169.254.255.1",
"169.254.255.2"
],
"routes_in": [],
"routes_out": []
},
{
"address_family": 6,
"customer_as": 65000,
"customer_ip": "2604:1380:45e1:5000::1",
"md5_enabled": false,
"md5_password": null,
"multihop": true,
"peer_as": 65530,
"peer_ips": [
"fc00:0000:0000:0000:0000:0000:0000:000e",
"fc00:0000:0000:0000:0000:0000:0000:000f"
],
"routes_in": [],
"routes_out": []
}
],
"api_url": "https://metadata.packet.net",
"phone_home_url": "http://tinkerbell.ny5.packet.net/phone-home",
"user_state_url": "http://tinkerbell.ny5.packet.net/events"
Expand Down
4 changes: 2 additions & 2 deletions website/content/v1.6/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ no_list: true
linkTitle: "Documentation"
cascade:
type: docs
lastRelease: v1.6.4
kubernetesRelease: "1.29.1"
lastRelease: v1.6.7
kubernetesRelease: "1.29.3"
prevKubernetesRelease: "1.28.3"
nvidiaContainerToolkitRelease: "v1.13.5"
nvidiaDriverRelease: "535.129.03"
Expand Down
Loading

0 comments on commit f737e64

Please sign in to comment.