/
device_utils_infiniband.go
152 lines (124 loc) · 4.44 KB
/
device_utils_infiniband.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package device
import (
"fmt"
"net"
"strings"
deviceConfig "github.com/lxc/lxd/lxd/device/config"
"github.com/lxc/lxd/lxd/state"
"github.com/lxc/lxd/shared/api"
)
// IBDevPrefix Infiniband devices prefix.
const IBDevPrefix = "infiniband.unix"
// infinibandDevices extracts the infiniband parent device from the supplied nic list and any free
// associated virtual functions (VFs) that are on the same card and port as the specified parent.
// This function expects that the supplied nic list does not include VFs that are already attached
// to running instances.
func infinibandDevices(nics *api.ResourcesNetwork, parent string) map[string]*api.ResourcesNetworkCardPort {
ibDevs := make(map[string]*api.ResourcesNetworkCardPort)
for _, card := range nics.Cards {
for _, port := range card.Ports {
// Skip non-infiniband ports.
if port.Protocol != "infiniband" {
continue
}
// Skip port if not parent.
if port.ID != parent {
continue
}
// Store infiniband port info.
ibDevs[port.ID] = &port
}
// Skip virtual function (VF) extraction if SRIOV isn't supported on port.
if card.SRIOV == nil {
continue
}
// Record if parent has been found as a physical function (PF).
parentDev, parentIsPF := ibDevs[parent]
for _, VF := range card.SRIOV.VFs {
for _, port := range VF.Ports {
// Skip non-infiniband VFs.
if port.Protocol != "infiniband" {
continue
}
// Skip VF if parent is a PF and VF is not on same port as parent.
if parentIsPF && parentDev.Port != port.Port {
continue
}
// Skip VF if parent isn't a PF and VF doesn't match parent name.
if !parentIsPF && port.ID != parent {
continue
}
// Store infiniband VF port info.
ibDevs[port.ID] = &port
}
}
}
return ibDevs
}
// infinibandAddDevices creates the UNIX devices for the provided IBF device and then configures the
// supplied runConfig with the Cgroup rules and mount instructions to pass the device into instance.
func infinibandAddDevices(s *state.State, devicesPath string, deviceName string, ibDev *api.ResourcesNetworkCardPort, runConf *deviceConfig.RunConfig) error {
if ibDev.Infiniband == nil {
return fmt.Errorf("No infiniband devices supplied")
}
// Add IsSM device if defined.
if ibDev.Infiniband.IsSMName != "" {
device := deviceConfig.Device{
"source": fmt.Sprintf("/dev/infiniband/%s", ibDev.Infiniband.IsSMName),
}
err := unixDeviceSetup(s, devicesPath, IBDevPrefix, deviceName, device, false, runConf)
if err != nil {
return err
}
}
// Add MAD device if defined.
if ibDev.Infiniband.MADName != "" {
device := deviceConfig.Device{
"source": fmt.Sprintf("/dev/infiniband/%s", ibDev.Infiniband.MADName),
}
err := unixDeviceSetup(s, devicesPath, IBDevPrefix, deviceName, device, false, runConf)
if err != nil {
return err
}
}
// Add Verb device if defined.
if ibDev.Infiniband.VerbName != "" {
device := deviceConfig.Device{
"source": fmt.Sprintf("/dev/infiniband/%s", ibDev.Infiniband.VerbName),
}
err := unixDeviceSetup(s, devicesPath, IBDevPrefix, deviceName, device, false, runConf)
if err != nil {
return err
}
}
return nil
}
// infinibandValidMAC validates an infiniband MAC address. Supports both short and long variants,
// e.g. "4a:c8:f9:1b:aa:57:ef:19" and "a0:00:0f:c0:fe:80:00:00:00:00:00:00:4a:c8:f9:1b:aa:57:ef:19".
func infinibandValidMAC(value string) error {
_, err := net.ParseMAC(value)
// Check valid lengths and delimiter.
if err != nil || (len(value) != 23 && len(value) != 59) || strings.ContainsAny(value, "-.") {
return fmt.Errorf("Invalid value, must be either 8 or 20 bytes of hex separated by colons")
}
return nil
}
// infinibandSetDevMAC detects whether the supplied MAC is a short or long form variant.
// If the short form variant is supplied then only the last 8 bytes of the ibDev device's hwaddr
// are changed. If the long form variant is supplied then the full 20 bytes of the ibDev device's
// hwaddr are changed.
func infinibandSetDevMAC(ibDev string, hwaddr string) error {
// Handle 20 byte variant, e.g. a0:00:14:c0:fe:80:00:00:00:00:00:00:4a:c8:f9:1b:aa:57:ef:19.
if len(hwaddr) == 59 {
return NetworkSetDevMAC(ibDev, hwaddr)
}
// Handle 8 byte variant, e.g. 4a:c8:f9:1b:aa:57:ef:19.
if len(hwaddr) == 23 {
curHwaddr, err := NetworkGetDevMAC(ibDev)
if err != nil {
return err
}
return NetworkSetDevMAC(ibDev, fmt.Sprintf("%s%s", curHwaddr[:36], hwaddr))
}
return fmt.Errorf("Invalid length")
}