99 "bytes"
1010 "context"
1111 "encoding/json"
12- stderrors "errors"
1312 "fmt"
1413 "io"
1514 "log"
@@ -71,6 +70,12 @@ type Address struct {
7170 Gateway string `json:"gateway"`
7271}
7372
73+ // BGPNeighbor holds BGP neighbor info from the equinixmetal metadata.
74+ type BGPNeighbor struct {
75+ AddressFamily int `json:"address_family"`
76+ PeerIPs []string `json:"peer_ips"`
77+ }
78+
7479const (
7580 // EquinixMetalUserDataEndpoint is the local metadata endpoint for Equinix.
7681 EquinixMetalUserDataEndpoint = "https://metadata.platformequinix.com/userdata"
@@ -122,27 +127,23 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
122127 // translate the int returned from bond mode metadata to the type needed by network resources
123128 bondMode := nethelpers .BondMode (uint8 (equinixMetadata .Network .Bonding .Mode ))
124129
125- // determine bond name and build list of interfaces enslaved by the bond
126- bondName := ""
127-
128130 hostInterfaces , err := safe .StateListAll [* network.LinkStatus ](ctx , st )
129131 if err != nil {
130132 return nil , fmt .Errorf ("error listing host interfaces: %w" , err )
131133 }
132134
133- slaveIndex := 0
135+ bondSlaveIndexes := map [string ]int {}
136+ firstBond := ""
134137
135138 for _ , iface := range equinixMetadata .Network .Interfaces {
136139 if iface .Bond == "" {
137140 continue
138141 }
139142
140- if bondName != "" && iface . Bond != bondName {
141- return nil , stderrors . New ( "encountered multiple bonds. this is unexpected in the equinix metal platform" )
143+ if firstBond == "" {
144+ firstBond = iface . Bond
142145 }
143146
144- bondName = iface .Bond
145-
146147 found := false
147148
148149 hostInterfaceIter := hostInterfaces .Iterator ()
@@ -154,17 +155,20 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
154155 if hostInterfaceIter .Value ().TypedSpec ().PermanentAddr .String () == iface .MAC {
155156 found = true
156157
158+ slaveIndex := bondSlaveIndexes [iface .Bond ]
159+
157160 networkConfig .Links = append (networkConfig .Links ,
158161 network.LinkSpecSpec {
159162 Name : hostInterfaceIter .Value ().Metadata ().ID (),
160163 Up : true ,
161164 BondSlave : network.BondSlave {
162- MasterName : bondName ,
165+ MasterName : iface . Bond ,
163166 SlaveIndex : slaveIndex ,
164167 },
165168 ConfigLayer : network .ConfigPlatform ,
166169 })
167- slaveIndex ++
170+
171+ bondSlaveIndexes [iface .Bond ]++
168172
169173 break
170174 }
@@ -173,39 +177,44 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
173177 if ! found {
174178 log .Printf ("interface with MAC %q wasn't found on the host, adding with the name from metadata" , iface .MAC )
175179
180+ slaveIndex := bondSlaveIndexes [iface .Bond ]
181+
176182 networkConfig .Links = append (networkConfig .Links ,
177183 network.LinkSpecSpec {
178184 ConfigLayer : network .ConfigPlatform ,
179185 Name : iface .Name ,
180186 Up : true ,
181187 BondSlave : network.BondSlave {
182- MasterName : bondName ,
188+ MasterName : iface . Bond ,
183189 SlaveIndex : slaveIndex ,
184190 },
185191 })
186- slaveIndex ++
192+
193+ bondSlaveIndexes [iface .Bond ]++
187194 }
188195 }
189196
190- bondLink := network.LinkSpecSpec {
191- ConfigLayer : network .ConfigPlatform ,
192- Name : bondName ,
193- Logical : true ,
194- Up : true ,
195- Kind : network .LinkKindBond ,
196- Type : nethelpers .LinkEther ,
197- BondMaster : network.BondMasterSpec {
198- Mode : bondMode ,
199- DownDelay : 200 ,
200- MIIMon : 100 ,
201- UpDelay : 200 ,
202- HashPolicy : nethelpers .BondXmitPolicyLayer34 ,
203- },
204- }
197+ for bondName := range bondSlaveIndexes {
198+ bondLink := network.LinkSpecSpec {
199+ ConfigLayer : network .ConfigPlatform ,
200+ Name : bondName ,
201+ Logical : true ,
202+ Up : true ,
203+ Kind : network .LinkKindBond ,
204+ Type : nethelpers .LinkEther ,
205+ BondMaster : network.BondMasterSpec {
206+ Mode : bondMode ,
207+ DownDelay : 200 ,
208+ MIIMon : 100 ,
209+ UpDelay : 200 ,
210+ HashPolicy : nethelpers .BondXmitPolicyLayer34 ,
211+ },
212+ }
205213
206- networkadapter .BondMasterSpec (& bondLink .BondMaster ).FillDefaults ()
214+ networkadapter .BondMasterSpec (& bondLink .BondMaster ).FillDefaults ()
207215
208- networkConfig .Links = append (networkConfig .Links , bondLink )
216+ networkConfig .Links = append (networkConfig .Links , bondLink )
217+ }
209218
210219 // 2. addresses
211220
@@ -233,7 +242,7 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
233242 networkConfig .Addresses = append (networkConfig .Addresses ,
234243 network.AddressSpecSpec {
235244 ConfigLayer : network .ConfigPlatform ,
236- LinkName : bondName ,
245+ LinkName : firstBond ,
237246 Address : ipAddr ,
238247 Scope : nethelpers .ScopeGlobal ,
239248 Flags : nethelpers .AddressFlags (nethelpers .AddressPermanent ),
@@ -249,6 +258,7 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
249258 }
250259
251260 // 3. routes
261+ var privateGateway netip.Addr
252262
253263 for _ , addr := range equinixMetadata .Network .Addresses {
254264 if ! (addr .Enabled && addr .Management ) {
@@ -275,7 +285,7 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
275285 route := network.RouteSpecSpec {
276286 ConfigLayer : network .ConfigPlatform ,
277287 Gateway : gw ,
278- OutLinkName : bondName ,
288+ OutLinkName : firstBond ,
279289 Table : nethelpers .TableMain ,
280290 Protocol : nethelpers .ProtocolStatic ,
281291 Type : nethelpers .TypeUnicast ,
@@ -298,6 +308,8 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
298308 return nil , err
299309 }
300310
311+ privateGateway = gw
312+
301313 dest , err := netip .ParsePrefix (privSubnet )
302314 if err != nil {
303315 return nil , err
@@ -307,7 +319,7 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
307319 ConfigLayer : network .ConfigPlatform ,
308320 Gateway : gw ,
309321 Destination : dest ,
310- OutLinkName : bondName ,
322+ OutLinkName : firstBond ,
311323 Table : nethelpers .TableMain ,
312324 Protocol : nethelpers .ProtocolStatic ,
313325 Type : nethelpers .TypeUnicast ,
@@ -347,6 +359,36 @@ func (p *EquinixMetal) ParseMetadata(ctx context.Context, equinixMetadata *Metad
347359 ProviderID : fmt .Sprintf ("equinixmetal://%s" , equinixMetadata .ID ),
348360 }
349361
362+ // 6. BGP neighbors
363+
364+ for _ , bgpNeighbor := range equinixMetadata .BGPNeighbors {
365+ if bgpNeighbor .AddressFamily != 4 {
366+ continue
367+ }
368+
369+ for _ , peerIP := range bgpNeighbor .PeerIPs {
370+ peer , err := netip .ParseAddr (peerIP )
371+ if err != nil {
372+ return nil , err
373+ }
374+
375+ route := network.RouteSpecSpec {
376+ ConfigLayer : network .ConfigPlatform ,
377+ Gateway : privateGateway ,
378+ Destination : netip .PrefixFrom (peer , 32 ),
379+ OutLinkName : firstBond ,
380+ Table : nethelpers .TableMain ,
381+ Protocol : nethelpers .ProtocolStatic ,
382+ Type : nethelpers .TypeUnicast ,
383+ Family : nethelpers .FamilyInet4 ,
384+ }
385+
386+ route .Normalize ()
387+
388+ networkConfig .Routes = append (networkConfig .Routes , route )
389+ }
390+ }
391+
350392 return networkConfig , nil
351393}
352394
0 commit comments