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

k8snetworkplumbingwg / sriov-network-operator / 19331737185

13 Nov 2025 12:35PM UTC coverage: 62.137% (-0.2%) from 62.366%
19331737185

push

github

web-flow
Merge pull request #902 from SchSeba/create_platform_and_orchestrator_packages

Create platform and orchestrator packages

319 of 659 new or added lines in 25 files covered. (48.41%)

42 existing lines in 10 files now uncovered.

8770 of 14114 relevant lines covered (62.14%)

0.69 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
)
34

35
var (
36
        ospNetworkDataFile = ospMetaDataDir + "/" + ospNetworkDataJSON
37
        ospMetaDataFile    = ospMetaDataDir + "/" + ospMetaDataJSON
38
)
39

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

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

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

NEW
65
        if ns == nil {
×
NEW
66
                err = o.createDevicesInfo()
×
NEW
67
                return err
×
NEW
68
        }
×
69

NEW
70
        o.createDevicesInfoFromNodeStatus(ns)
×
NEW
71
        return nil
×
72
}
73

74
// Name returns the name of the OpenStack platform.
NEW
75
func (o *Openstack) Name() string {
×
NEW
76
        return "OpenStack"
×
NEW
77
}
×
78

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

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

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

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

NEW
112
        devices := pci.Devices
×
NEW
113
        if len(devices) == 0 {
×
NEW
114
                return nil, fmt.Errorf("DiscoverSriovDevicesVirtual(): could not retrieve PCI devices")
×
NEW
115
        }
×
116

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

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

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

NEW
163
                iface.TotalVfs = 1
×
NEW
164
                iface.NumVfs = 1
×
NEW
165

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

×
NEW
177
                pfList = append(pfList, iface)
×
178
        }
NEW
179
        return pfList, nil
×
180
}
181

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

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

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

NEW
199
        if metaData == nil || networkData == nil {
×
NEW
200
                o.openStackDevicesInfo = make(OSPDevicesInfo)
×
NEW
201
                return nil
×
NEW
202
        }
×
203

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

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

NEW
224
        devices := pci.Devices
×
NEW
225
        if len(devices) == 0 {
×
NEW
226
                return fmt.Errorf("CreateOpenstackDevicesInfo(): could not retrieve PCI devices")
×
NEW
227
        }
×
228

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

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

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

NEW
257
                for _, link := range networkData.Links {
×
NEW
258
                        if macAddress == link.EthernetMac {
×
NEW
259
                                for _, network := range networkData.Networks {
×
NEW
260
                                        if network.Link == link.ID {
×
NEW
261
                                                networkID := sriovnetworkv1.OpenstackNetworkID.String() + ":" + network.NetworkID
×
NEW
262
                                                devicesInfo[device.Address] = &OSPDeviceInfo{MacAddress: macAddress, NetworkID: networkID}
×
NEW
263
                                        }
×
264
                                }
265
                        }
266
                }
267
        }
268

NEW
269
        o.openStackDevicesInfo = devicesInfo
×
NEW
270
        return nil
×
271
}
272

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

NEW
279
        o.openStackDevicesInfo = devicesInfo
×
280
}
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