• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

k8snetworkplumbingwg / sriov-network-operator / 19889722677

03 Dec 2025 09:56AM UTC coverage: 63.243% (+1.1%) from 62.149%
19889722677

push

github

web-flow
Merge pull request #899 from SchSeba/support_aws

Support aws

251 of 353 new or added lines in 11 files covered. (71.1%)

11 existing lines in 3 files now uncovered.

9081 of 14359 relevant lines covered (63.24%)

0.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pkg/platform/openstack/openstack.go
1
package openstack
2

3
import (
4
        "fmt"
5
        "strconv"
6

7
        "github.com/jaypipes/ghw"
8
        "sigs.k8s.io/controller-runtime/pkg/log"
9

10
        dputils "github.com/k8snetworkplumbingwg/sriov-network-device-plugin/pkg/utils"
11

12
        sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
13
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
14
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/helper"
15
        plugin "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/plugins"
16
        virtualplugin "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/plugins/virtual"
17
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
18
)
19

20
const (
21
        varConfigPath      = "/var/config"
22
        ospMetaDataBaseDir = "/openstack/2018-08-27"
23
        ospMetaDataDir     = varConfigPath + ospMetaDataBaseDir
24
        ospMetaDataBaseURL = "http://169.254.169.254" + ospMetaDataBaseDir
25
        ospNetworkDataJSON = "network_data.json"
26
        ospMetaDataJSON    = "meta_data.json"
27
        ospNetworkDataURL  = ospMetaDataBaseURL + "/" + ospNetworkDataJSON
28
        ospMetaDataURL     = ospMetaDataBaseURL + "/" + ospMetaDataJSON
29
        // Config drive is defined as an iso9660 or vfat (deprecated) drive
30
        // with the "config-2" label.
31
        //https://docs.openstack.org/nova/latest/user/config-drive.html
32
        configDriveLabel = "config-2"
33
        // openstackNetworkIDPrefix is the prefix used for OpenStack network ID in NetFilter field.
34
        // Format: "openstack/NetworkID:<network-uuid>"
35
        openstackNetworkIDPrefix = "openstack/NetworkID:"
36
)
37

38
var (
39
        ospNetworkDataFile = ospMetaDataDir + "/" + ospNetworkDataJSON
40
        ospMetaDataFile    = ospMetaDataDir + "/" + ospMetaDataJSON
41
)
42

43
// Openstack implements the platform.Interface for OpenStack virtual platforms.
44
// It handles SR-IOV device discovery for virtual functions in OpenStack environments,
45
// using metadata from the OpenStack metadata service or config drive.
46
type Openstack struct {
47
        hostHelpers          helper.HostHelpersInterface
48
        openStackDevicesInfo OSPDevicesInfo
49
}
50

51
// New creates a new Openstack platform instance.
52
// Returns a configured Openstack platform or an error if initialization fails.
53
func New(hostHelper helper.HostHelpersInterface) (*Openstack, error) {
×
54
        return &Openstack{
×
55
                hostHelpers: hostHelper,
×
56
        }, nil
×
57
}
×
58

59
// Init initializes the OpenStack platform by loading device information.
60
// If a checkpoint exists, it loads device info from the saved node state.
61
// Otherwise, it queries the OpenStack metadata service or config drive.
62
func (o *Openstack) Init() error {
×
63
        ns, err := o.hostHelpers.GetCheckPointNodeState()
×
64
        if err != nil {
×
65
                return err
×
66
        }
×
67

68
        if ns == nil {
×
69
                err = o.createDevicesInfo()
×
70
                return err
×
71
        }
×
72

73
        o.createDevicesInfoFromNodeStatus(ns)
×
74
        return nil
×
75
}
76

77
// Name returns the name of the OpenStack platform.
78
func (o *Openstack) Name() string {
×
NEW
79
        return string(consts.VirtualOpenStack)
×
80
}
×
81

82
// GetVendorPlugins returns the virtual plugin as the main plugin for OpenStack.
83
// OpenStack platforms only use the virtual plugin, with no additional plugins.
84
func (o *Openstack) GetVendorPlugins(_ *sriovnetworkv1.SriovNetworkNodeState) (plugin.VendorPlugin, []plugin.VendorPlugin, error) {
×
85
        virtual, err := virtualplugin.NewVirtualPlugin(o.hostHelpers)
×
86
        return virtual, []plugin.VendorPlugin{}, err
×
87
}
×
88

89
// SystemdGetVendorPlugin returns the appropriate plugin for systemd mode on OpenStack.
90
// For PhasePre, returns the virtual plugin.
91
// For PhasePost, returns nil as no post-configuration is needed for virtual platforms.
92
func (o *Openstack) SystemdGetVendorPlugin(phase string) (plugin.VendorPlugin, error) {
×
93
        switch phase {
×
94
        case consts.PhasePre:
×
95
                return virtualplugin.NewVirtualPlugin(o.hostHelpers)
×
96
        case consts.PhasePost:
×
97
                return nil, nil
×
98
        default:
×
99
                return nil, fmt.Errorf("invalid phase %s", phase)
×
100
        }
101
}
102

103
// DiscoverSriovDevices discovers VFs on the OpenStack virtual platform.
104
// Each network device is treated as a single VF with TotalVfs=1 and NumVfs=1.
105
// Device metadata (MAC address, network ID) is enriched from OpenStack metadata.
106
func (o *Openstack) DiscoverSriovDevices() ([]sriovnetworkv1.InterfaceExt, error) {
×
107
        log.Log.V(2).Info("DiscoverSriovDevices()")
×
108
        pfList := []sriovnetworkv1.InterfaceExt{}
×
109

×
110
        pci, err := ghw.PCI()
×
111
        if err != nil {
×
112
                return nil, fmt.Errorf("DiscoverSriovDevicesVirtual(): error getting PCI info: %v", err)
×
113
        }
×
114

115
        devices := pci.Devices
×
116
        if len(devices) == 0 {
×
117
                return nil, fmt.Errorf("DiscoverSriovDevicesVirtual(): could not retrieve PCI devices")
×
118
        }
×
119

120
        for _, device := range devices {
×
121
                devClass, err := strconv.ParseInt(device.Class.ID, 16, 64)
×
122
                if err != nil {
×
123
                        log.Log.Error(err, "DiscoverSriovDevicesVirtual(): unable to parse device class for device, skipping",
×
124
                                "device", device)
×
125
                        continue
×
126
                }
127
                if devClass != consts.NetClass {
×
128
                        // Not network device
×
129
                        continue
×
130
                }
131

132
                deviceInfo, exist := o.openStackDevicesInfo[device.Address]
×
133
                if !exist {
×
134
                        log.Log.Error(nil, "DiscoverSriovDevicesVirtual(): unable to find device in devicesInfo list, skipping",
×
135
                                "device", device.Address)
×
136
                        continue
×
137
                }
138
                netFilter := deviceInfo.NetworkID
×
139
                metaMac := deviceInfo.MacAddress
×
140

×
141
                driver, err := dputils.GetDriverName(device.Address)
×
142
                if err != nil {
×
143
                        log.Log.Error(err, "DiscoverSriovDevicesVirtual(): unable to parse device driver for device, skipping",
×
144
                                "device", device)
×
145
                        continue
×
146
                }
147
                iface := sriovnetworkv1.InterfaceExt{
×
148
                        PciAddress: device.Address,
×
149
                        Driver:     driver,
×
150
                        Vendor:     device.Vendor.ID,
×
151
                        DeviceID:   device.Product.ID,
×
152
                        NetFilter:  netFilter,
×
153
                }
×
154
                if mtu := o.hostHelpers.GetNetdevMTU(device.Address); mtu > 0 {
×
155
                        iface.Mtu = mtu
×
156
                }
×
157
                if name := o.hostHelpers.TryToGetVirtualInterfaceName(device.Address); name != "" {
×
158
                        iface.Name = name
×
159
                        if iface.Mac = o.hostHelpers.GetNetDevMac(name); iface.Mac == "" {
×
160
                                iface.Mac = metaMac
×
161
                        }
×
162
                        iface.LinkSpeed = o.hostHelpers.GetNetDevLinkSpeed(name)
×
163
                        iface.LinkType = o.hostHelpers.GetLinkType(name)
×
164
                }
165

166
                iface.TotalVfs = 1
×
167
                iface.NumVfs = 1
×
168

×
169
                vf := sriovnetworkv1.VirtualFunction{
×
170
                        PciAddress: device.Address,
×
171
                        Driver:     driver,
×
172
                        VfID:       0,
×
173
                        Vendor:     iface.Vendor,
×
174
                        DeviceID:   iface.DeviceID,
×
175
                        Mtu:        iface.Mtu,
×
176
                        Mac:        iface.Mac,
×
177
                }
×
178
                iface.VFs = append(iface.VFs, vf)
×
179

×
180
                pfList = append(pfList, iface)
×
181
        }
182
        return pfList, nil
×
183
}
184

185
// DiscoverBridges is not supported on OpenStack virtual platforms.
186
// Returns ErrOperationNotSupportedByPlatform as OpenStack does not support software bridge management.
187
func (o *Openstack) DiscoverBridges() (sriovnetworkv1.Bridges, error) {
×
188
        return sriovnetworkv1.Bridges{}, vars.ErrOperationNotSupportedByPlatform
×
189
}
×
190

191
// CreateOpenstackDevicesInfo create the openstack device info map
192
func (o *Openstack) createDevicesInfo() error {
×
193
        log.Log.Info("CreateDevicesInfo()")
×
194
        devicesInfo := make(OSPDevicesInfo)
×
195

×
196
        metaData, networkData, err := getOpenstackData(true)
×
197
        if err != nil {
×
198
                log.Log.Error(err, "failed to read OpenStack data")
×
199
                return err
×
200
        }
×
201

202
        if metaData == nil || networkData == nil {
×
203
                o.openStackDevicesInfo = make(OSPDevicesInfo)
×
204
                return nil
×
205
        }
×
206

207
        // use this for hw pass throw interfaces
208
        for _, device := range metaData.Devices {
×
209
                for _, link := range networkData.Links {
×
210
                        if device.Mac == link.EthernetMac {
×
211
                                for _, network := range networkData.Networks {
×
212
                                        if network.Link == link.ID {
×
NEW
213
                                                networkID := openstackNetworkIDPrefix + network.NetworkID
×
214
                                                devicesInfo[device.Address] = &OSPDeviceInfo{MacAddress: device.Mac, NetworkID: networkID}
×
215
                                        }
×
216
                                }
217
                        }
218
                }
219
        }
220

221
        // for vhostuser interface type we check the interfaces on the node
222
        pci, err := ghw.PCI()
×
223
        if err != nil {
×
224
                return fmt.Errorf("CreateOpenstackDevicesInfo(): error getting PCI info: %v", err)
×
225
        }
×
226

227
        devices := pci.Devices
×
228
        if len(devices) == 0 {
×
229
                return fmt.Errorf("CreateOpenstackDevicesInfo(): could not retrieve PCI devices")
×
230
        }
×
231

232
        for _, device := range devices {
×
233
                if _, exist := devicesInfo[device.Address]; exist {
×
234
                        //we already discover the device via openstack metadata
×
235
                        continue
×
236
                }
237

238
                devClass, err := strconv.ParseInt(device.Class.ID, 16, 64)
×
239
                if err != nil {
×
240
                        log.Log.Error(err, "CreateOpenstackDevicesInfo(): unable to parse device class for device, skipping",
×
241
                                "device", device)
×
242
                        continue
×
243
                }
244
                if devClass != consts.NetClass {
×
245
                        // Not network device
×
246
                        continue
×
247
                }
248

249
                macAddress := ""
×
250
                if name := o.hostHelpers.TryToGetVirtualInterfaceName(device.Address); name != "" {
×
251
                        if mac := o.hostHelpers.GetNetDevMac(name); mac != "" {
×
252
                                macAddress = mac
×
253
                        }
×
254
                }
255
                if macAddress == "" {
×
256
                        // we didn't manage to find a mac address for the nic skipping
×
257
                        continue
×
258
                }
259

260
                for _, link := range networkData.Links {
×
261
                        if macAddress == link.EthernetMac {
×
262
                                for _, network := range networkData.Networks {
×
263
                                        if network.Link == link.ID {
×
NEW
264
                                                networkID := openstackNetworkIDPrefix + network.NetworkID
×
265
                                                devicesInfo[device.Address] = &OSPDeviceInfo{MacAddress: macAddress, NetworkID: networkID}
×
266
                                        }
×
267
                                }
268
                        }
269
                }
270
        }
271

272
        o.openStackDevicesInfo = devicesInfo
×
273
        return nil
×
274
}
275

276
func (o *Openstack) createDevicesInfoFromNodeStatus(networkState *sriovnetworkv1.SriovNetworkNodeState) {
×
277
        devicesInfo := make(OSPDevicesInfo)
×
278
        for _, iface := range networkState.Status.Interfaces {
×
279
                devicesInfo[iface.PciAddress] = &OSPDeviceInfo{MacAddress: iface.Mac, NetworkID: iface.NetFilter}
×
280
        }
×
281

282
        o.openStackDevicesInfo = devicesInfo
×
283
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc