Skip to content

Commit a66dce3

Browse files
authored
Merge pull request #75 from adrianchiris/support-socket-direct
chore: simplify GetVfRepresentor function
2 parents 0ecc3a3 + 1a1e052 commit a66dce3

File tree

3 files changed

+167
-39
lines changed

3 files changed

+167
-39
lines changed

sriovnet_helper.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,6 @@ func vfPCIDevNameFromVfIndex(pfNetdevName string, vfIndex int) (string, error) {
117117
return pciAddress, err
118118
}
119119

120-
func getPCIFromDeviceName(netdevName string) (string, error) {
121-
symbolicLink := filepath.Join(NetSysDir, netdevName, pcidevPrefix)
122-
pciAddress, err := readPCIsymbolicLink(symbolicLink)
123-
if err != nil {
124-
err = fmt.Errorf("%v for netdevice %s", err, netdevName)
125-
}
126-
return pciAddress, err
127-
}
128-
129120
func GetVfPciDevList(pfNetdevName string) ([]string, error) {
130121
var i int
131122
devDirName := netDevDeviceDir(pfNetdevName)

sriovnet_switchdev.go

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717
package sriovnet
1818

1919
import (
20-
"bytes"
2120
"errors"
2221
"fmt"
2322
"net"
@@ -139,50 +138,30 @@ func GetUplinkRepresentor(pciAddress string) (string, error) {
139138

140139
// GetVfRepresentor returns the VF representor netdev name for a given uplink netdev and vfIndex.
141140
func GetVfRepresentor(uplink string, vfIndex int) (string, error) {
142-
swIDFile := filepath.Join(NetSysDir, uplink, netdevPhysSwitchID)
143-
physSwitchID, err := utilfs.Fs.ReadFile(swIDFile)
144-
if err != nil || len(physSwitchID) == 0 {
145-
return "", fmt.Errorf("cant get uplink %s switch id", uplink)
141+
// if uplink is not switchdev, return error early
142+
if !isSwitchdev(uplink) {
143+
return "", fmt.Errorf("uplink %s is not a switchdev", uplink)
146144
}
147145

148-
// get uplink pci address and pci function number
149-
pfPCIAddress, err := getPCIFromDeviceName(uplink)
150-
if err != nil {
151-
return "", fmt.Errorf("failed to get pci address for uplink %s: %v", uplink, err)
152-
}
153-
PCIFuncAddress, err := strconv.Atoi(string((pfPCIAddress[len(pfPCIAddress)-1])))
154-
if err != nil {
155-
return "", fmt.Errorf("failed to get pci function number for uplink %s, pfPCIAddress %s: %w",
156-
uplink, pfPCIAddress, err)
157-
}
158-
159-
pfSubsystemPath := filepath.Join(NetSysDir, uplink, "subsystem")
160-
devices, err := utilfs.Fs.ReadDir(pfSubsystemPath)
146+
// representors of a specific uplinkare expected to be linked with the same device as the uplink
147+
pfLinkPath := filepath.Join(NetSysDir, uplink, "device", "net")
148+
devices, err := utilfs.Fs.ReadDir(pfLinkPath)
161149
if err != nil {
162150
return "", err
163151
}
164152
for _, device := range devices {
165-
devicePath := filepath.Join(NetSysDir, device.Name())
166-
deviceSwIDFile := filepath.Join(devicePath, netdevPhysSwitchID)
167-
deviceSwID, err := utilfs.Fs.ReadFile(deviceSwIDFile)
168-
if err != nil || !bytes.Equal(deviceSwID, physSwitchID) {
169-
continue
170-
}
171-
172153
physPortNameStr, err := getNetDevPhysPortName(device.Name())
173154
if err != nil {
174155
continue
175156
}
176157

177-
pfRepIndex, vfRepIndex, err := parseIndexFromPhysPortName(physPortNameStr, vfPortRepRegex)
158+
_, vfRepIndex, err := parseIndexFromPhysPortName(physPortNameStr, vfPortRepRegex)
178159
if err != nil {
179160
continue
180161
}
181162

182-
// check pfRepIndex matches the uplink PF function number (e.g. 0000:03:00.0 -> 0) and
183-
// vfRepIndex matches the vfIndex
184-
if pfRepIndex == PCIFuncAddress && vfRepIndex == vfIndex {
185-
// At this point we're confident we have a representor.
163+
// check vfRepIndex matches the vfIndex
164+
if vfRepIndex == vfIndex {
186165
return device.Name(), nil
187166
}
188167
}

sriovnet_switchdev_test.go

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,164 @@ func setupDPUConfigFileForPort(t *testing.T, uplink, portName, fileContent strin
156156
assert.NoError(t, err)
157157
}
158158

159+
func setupRepresentorEnvForGetVfRepresentor(t *testing.T, uplink *repContext, vfReps []*repContext) func() {
160+
var err error
161+
teardown := setupFakeFs(t)
162+
163+
defer func() {
164+
if err != nil {
165+
teardown()
166+
t.Errorf("setupRepresentorEnvForGetVfRepresentor, got %v", err)
167+
}
168+
}()
169+
170+
// Create the uplink device/net directory structure
171+
pfNetPath := filepath.Join(NetSysDir, uplink.Name, "device", "net")
172+
err = utilfs.Fs.MkdirAll(pfNetPath, os.FileMode(0755))
173+
if err != nil {
174+
teardown()
175+
t.Errorf("setupRepresentorEnvForGetVfRepresentor, got %v", err)
176+
}
177+
178+
for _, rep := range vfReps {
179+
// Create representor directory under the uplink's device/net path
180+
repPath := filepath.Join(pfNetPath, rep.Name)
181+
repLink := filepath.Join(NetSysDir, rep.Name)
182+
183+
err = utilfs.Fs.MkdirAll(repPath, os.FileMode(0755))
184+
if err != nil {
185+
teardown()
186+
t.Errorf("setupRepresentorEnvForGetVfRepresentor, got %v", err)
187+
}
188+
189+
// Create symlink from /sys/class/net/<rep_name> to the rep path
190+
_ = utilfs.Fs.Symlink(repPath, repLink)
191+
192+
if err = setUpRepPhysFiles(rep); err != nil {
193+
teardown()
194+
t.Errorf("setupRepresentorEnvForGetVfRepresentor, got %v", err)
195+
}
196+
}
197+
198+
// create phys_port_name and phys_switch_id files for the uplink
199+
if err = setUpRepPhysFiles(uplink); err != nil {
200+
teardown()
201+
t.Errorf("setupRepresentorEnvForGetVfRepresentor, got %v", err)
202+
}
203+
204+
return teardown
205+
}
206+
207+
func TestGetVfRepresentor(t *testing.T) {
208+
tcases := []struct {
209+
name string
210+
uplink *repContext
211+
vfReps []*repContext
212+
vfIndex int
213+
expectedVFRep string
214+
shouldFail bool
215+
}{
216+
{
217+
name: "VF representor found",
218+
uplink: &repContext{Name: "p0", PhysPortName: "p0", PhysSwitchID: "c2cfc60003a1420c"},
219+
vfReps: []*repContext{
220+
{Name: "eth0", PhysPortName: "pf0vf0", PhysSwitchID: "c2cfc60003a1420c"},
221+
{Name: "eth1", PhysPortName: "pf0vf1", PhysSwitchID: "c2cfc60003a1420c"},
222+
{Name: "eth2", PhysPortName: "pf0vf2", PhysSwitchID: "c2cfc60003a1420c"},
223+
},
224+
vfIndex: 2,
225+
expectedVFRep: "eth2",
226+
shouldFail: false,
227+
},
228+
{
229+
name: "VF representor not found - index doesn't exist",
230+
uplink: &repContext{Name: "p0", PhysPortName: "p0", PhysSwitchID: "c2cfc60003a1420c"},
231+
vfReps: []*repContext{
232+
{Name: "eth0", PhysPortName: "pf0vf0", PhysSwitchID: "c2cfc60003a1420c"},
233+
{Name: "eth1", PhysPortName: "pf0vf1", PhysSwitchID: "c2cfc60003a1420c"},
234+
{Name: "eth2", PhysPortName: "pf0vf2", PhysSwitchID: "c2cfc60003a1420c"},
235+
},
236+
vfIndex: 5,
237+
expectedVFRep: "",
238+
shouldFail: true,
239+
},
240+
{
241+
name: "VF representor not found - no representors",
242+
uplink: &repContext{Name: "p0", PhysPortName: "p0", PhysSwitchID: "c2cfc60003a1420c"},
243+
vfReps: []*repContext{},
244+
vfIndex: 0,
245+
expectedVFRep: "",
246+
shouldFail: true,
247+
},
248+
{
249+
name: "VF representor not found - invalid phys_port_name",
250+
uplink: &repContext{Name: "p0", PhysPortName: "p0", PhysSwitchID: "c2cfc60003a1420c"},
251+
vfReps: []*repContext{
252+
{Name: "eth0", PhysPortName: "invalid", PhysSwitchID: "c2cfc60003a1420c"},
253+
{Name: "eth1", PhysPortName: "pf0sf1", PhysSwitchID: "c2cfc60003a1420c"}, // SF instead of VF
254+
},
255+
vfIndex: 0,
256+
expectedVFRep: "",
257+
shouldFail: true,
258+
},
259+
{
260+
name: "VF representor not found - missing phys_port_name",
261+
uplink: &repContext{Name: "p0", PhysPortName: "p0", PhysSwitchID: "c2cfc60003a1420c"},
262+
vfReps: []*repContext{
263+
{Name: "eth0", PhysPortName: "", PhysSwitchID: "c2cfc60003a1420c"}, // No phys_port_name
264+
{Name: "eth1", PhysPortName: "pf0vf1", PhysSwitchID: "c2cfc60003a1420c"},
265+
},
266+
vfIndex: 0,
267+
expectedVFRep: "",
268+
shouldFail: true,
269+
},
270+
{
271+
name: "uplink is not switchdev",
272+
uplink: &repContext{Name: "eth0", PhysPortName: "", PhysSwitchID: ""},
273+
vfReps: []*repContext{},
274+
vfIndex: 0,
275+
expectedVFRep: "",
276+
shouldFail: true,
277+
},
278+
{
279+
name: "VF representor found with mixed representors",
280+
uplink: &repContext{Name: "p0", PhysPortName: "p0", PhysSwitchID: "c2cfc60003a1420c"},
281+
vfReps: []*repContext{
282+
{Name: "eth0", PhysPortName: "invalid", PhysSwitchID: "c2cfc60003a1420c"}, // Invalid
283+
{Name: "eth1", PhysPortName: "pf0vf0", PhysSwitchID: "c2cfc60003a1420c"},
284+
{Name: "eth2", PhysPortName: "pf0sf1", PhysSwitchID: "c2cfc60003a1420c"}, // SF rep
285+
{Name: "eth3", PhysPortName: "pf0vf2", PhysSwitchID: "c2cfc60003a1420c"},
286+
},
287+
vfIndex: 2,
288+
expectedVFRep: "eth3",
289+
shouldFail: false,
290+
},
291+
}
292+
293+
for _, tcase := range tcases {
294+
t.Run(tcase.name, func(t *testing.T) {
295+
teardown := setupRepresentorEnvForGetVfRepresentor(t, tcase.uplink, tcase.vfReps)
296+
defer teardown()
297+
vfRep, err := GetVfRepresentor(tcase.uplink.Name, tcase.vfIndex)
298+
if tcase.shouldFail {
299+
assert.Error(t, err)
300+
} else {
301+
assert.NoError(t, err)
302+
assert.Equal(t, tcase.expectedVFRep, vfRep)
303+
}
304+
})
305+
}
306+
307+
// Test edge case: uplink directory doesn't exist (filesystem error)
308+
t.Run("uplink directory doesn't exist", func(t *testing.T) {
309+
teardown := setupFakeFs(t)
310+
defer teardown()
311+
312+
_, err := GetVfRepresentor("nonexistent_uplink", 0)
313+
assert.Error(t, err)
314+
})
315+
}
316+
159317
func TestGetUplinkRepresentorWithPhysPortName(t *testing.T) {
160318
tcases := []struct {
161319
name string

0 commit comments

Comments
 (0)