Skip to content

Commit 0cc1c86

Browse files
committed
Remove driver version check
Avoid checking the driver version against a user defined map. If the netlink collector is not supported by the Physical Function, the next provided collector (e.g. `sysfs`) is used. Signed-off-by: Andrea Panattoni <[email protected]>
1 parent b9c8664 commit 0cc1c86

File tree

11 files changed

+37
-294
lines changed

11 files changed

+37
-294
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The SR-IOV Network Metrics Exporter is designed with the Kubernetes SR-IOV stack
99
The sysfs collector for Virtual Function telemetry supports NICs with drivers that implement the SR-IOV sysfs management interface e.g. ice, i40e, mlnx_en and mlnx_ofed.
1010

1111
The netlink collector relies on driver support and a kernel version of 4.4 or higher.
12-
To support netlink, we recommend these driver versions:
12+
Also, the following minimum driver versions are required for this collector:
1313
- `i40e` - 2.11+ for Intel® 700 series NICs
1414
- `ice` - 1.2+ for Intel® 800 series NICs
1515
- `mlx5_core` - 5.15+ for Mellanox NICs

collectors/sriovdev.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,10 @@ import (
1515
"github.com/prometheus/client_golang/prometheus"
1616

1717
"github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter/pkg/utils"
18-
19-
"github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter/pkg/drvinfo"
2018
)
2119

2220
const (
23-
noNumaInfo = "-1"
24-
supportedDriversDbPath = "/etc/sriov-network-metrics-exporter/drivers.yaml"
21+
noNumaInfo = "-1"
2522
)
2623

2724
var (
@@ -35,8 +32,6 @@ var (
3532
vfStatsSubsystem = "vf"
3633
vfStatsCollectorName = "vfstats"
3734

38-
supportedDrivers drvinfo.SupportedDrivers
39-
4035
devfs fs.FS
4136
netfs fs.FS
4237
)
@@ -47,7 +42,6 @@ type vfsPCIAddr map[string]string
4742
// init runs the registration for this collector on package import
4843
func init() {
4944
flag.Var(&collectorPriority, "collector.vfstatspriority", "Priority of collectors")
50-
supportedDrivers = drvinfo.NewSupportedDrivers(supportedDriversDbPath)
5145
register(vfStatsCollectorName, enabled, createSriovDevCollector)
5246
}
5347

collectors/sriovdev_readers.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"strconv"
1212
"strings"
1313

14-
"github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter/pkg/drvinfo"
1514
"github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter/pkg/utils"
1615
"github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter/pkg/vfstats"
1716
)
@@ -49,18 +48,12 @@ func getStatsReader(pf string, priority []string) sriovStatReader {
4948

5049
log.Printf("%s does not support sysfs collector, directory '%s' does not exist", pf, filepath.Join(pf, "/device/sriov"))
5150
case "netlink":
52-
info, err := drvinfo.GetDriverInfo(pf)
53-
if err != nil {
54-
log.Printf("failed to get driver info error %v", err)
55-
return nil
56-
}
57-
58-
if supportedDrivers.IsDriverSupported(info) {
51+
if vfstats.DoesPfSupportNetlink(pf) {
5952
log.Printf("%s - using netlink collector", pf)
6053
return netlinkReader{vfstats.VfStats(pf)}
6154
}
6255

63-
log.Printf("%s does not support netlink collector, %+v driver not supported", pf, info)
56+
log.Printf("%s does not support netlink collector", pf)
6457
default:
6558
log.Printf("%s - '%s' collector not supported", pf, collector)
6659
}

collectors/sriovdev_readers_test.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,26 @@ import (
44
"io/fs"
55
"testing/fstest"
66

7-
"github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter/pkg/drvinfo"
87
"github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter/pkg/vfstats"
8+
"github.com/vishvananda/netlink"
99

1010
. "github.com/onsi/ginkgo/v2"
1111
. "github.com/onsi/gomega"
1212
)
1313

1414
var _ = DescribeTable("test getting stats reader for pf", // getStatsReader
15-
func(pf string, priority []string, fsys fs.FS, driver *drvinfo.DriverInfo, expected sriovStatReader, logs ...string) {
15+
func(pf string, priority []string, fsys fs.FS, link netlink.Link, expected sriovStatReader, logs ...string) {
1616
netfs = fsys
1717

18-
// TODO: replace with ethtool mock
19-
drvinfo.GetDriverInfo = func(name string) (*drvinfo.DriverInfo, error) {
20-
return driver, nil
18+
if link != nil {
19+
vfstats.GetLink = func(name string) (netlink.Link, error) {
20+
return link, nil
21+
}
22+
DeferCleanup(func() {
23+
vfstats.GetLink = netlink.LinkByName
24+
})
2125
}
2226

23-
// TODO: replace with fstest.MapFS entry
24-
supportedDrivers = drvinfo.SupportedDrivers{Drivers: drvinfo.DriversList{Drivers: []drvinfo.DriverInfo{*driver}}, DbFilePath: ""}
25-
2627
statsReader := getStatsReader(pf, priority)
2728

2829
if expected != nil {
@@ -37,22 +38,22 @@ var _ = DescribeTable("test getting stats reader for pf", // getStatsReader
3738
"ens785f0",
3839
[]string{"sysfs", "netlink"},
3940
fstest.MapFS{"ens785f0/device/sriov": {Mode: fs.ModeDir}},
40-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
41+
nil,
4142
sysfsReader{"/sys/class/net/%s/device/sriov/%s/stats"},
4243
"ens785f0 - using sysfs collector"),
4344
Entry("without sysfs support",
4445
"ens785f0",
4546
[]string{"sysfs", "netlink"},
4647
fstest.MapFS{},
47-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
48+
&netlink.Device{LinkAttrs: netlink.LinkAttrs{Vfs: []netlink.VfInfo{}}}, //nolint:govet
4849
netlinkReader{vfstats.VfStats("ens785f0")},
4950
"ens785f0 does not support sysfs collector",
5051
"ens785f0 - using netlink collector"),
5152
Entry("without any collector support",
5253
"ens785f0",
5354
[]string{"unsupported_collector"},
5455
fstest.MapFS{},
55-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
56+
nil,
5657
nil,
5758
"ens785f0 - 'unsupported_collector' collector not supported"),
5859
)

collectors/sriovdev_test.go

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"net"
77
"testing/fstest"
88

9-
"github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter/pkg/drvinfo"
109
"github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter/pkg/vfstats"
1110

1211
. "github.com/onsi/ginkgo/v2"
@@ -21,19 +20,11 @@ var _ = AfterEach(func() {
2120
})
2221

2322
var _ = DescribeTable("test vf stats collection", // Collect
24-
func(priority []string, fsys fs.FS, driver *drvinfo.DriverInfo, link netlink.Device, expected []metric, logs ...string) {
23+
func(priority []string, fsys fs.FS, link netlink.Device, expected []metric, logs ...string) {
2524
devfs = fsys
2625
netfs = fsys
2726
collectorPriority = priority
2827

29-
// TODO: replace with ethtool mock
30-
drvinfo.GetDriverInfo = func(name string) (*drvinfo.DriverInfo, error) {
31-
return driver, nil
32-
}
33-
34-
// TODO: replace with fstest.MapFS entry
35-
supportedDrivers = drvinfo.SupportedDrivers{Drivers: drvinfo.DriversList{Drivers: []drvinfo.DriverInfo{*driver}}, DbFilePath: ""}
36-
3728
vfstats.GetLink = func(name string) (netlink.Link, error) {
3829
return &link, nil
3930
}
@@ -71,7 +62,6 @@ var _ = DescribeTable("test vf stats collection", // Collect
7162
"t_ens785f0/device/sriov/0/stats/tx_packets": {Data: []byte("8")},
7263
"t_ens785f0/device/sriov/1/stats/rx_packets": {Data: []byte("16")},
7364
"t_ens785f0/device/sriov/1/stats/tx_packets": {Data: []byte("32")}},
74-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
7565
nil,
7666
[]metric{
7767
{map[string]string{"numa_node": "0", "pciAddr": "0000:1d:01.0", "pf": "t_ens785f0", "vf": "0"}, 4},
@@ -92,7 +82,6 @@ var _ = DescribeTable("test vf stats collection", // Collect
9282
"0000:2e:00.0/class": {Data: []byte("0x020000")},
9383
"0000:2e:00.0/virtfn0": {Data: []byte("/sys/devices/0000:2e:01.0"), Mode: fs.ModeSymlink},
9484
"0000:2e:00.0/virtfn1": {Data: []byte("/sys/devices/0000:2e:01.1"), Mode: fs.ModeSymlink}},
95-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
9685
netlink.Device{LinkAttrs: netlink.LinkAttrs{Vfs: []netlink.VfInfo{
9786
{0, net.HardwareAddr{}, 0, 0, 0, true, 0, 0, 0, 11, 12, 13, 14, 15, 16, 17, 18, 0, 0}, //nolint:govet
9887
{1, net.HardwareAddr{}, 0, 0, 0, true, 0, 0, 0, 21, 22, 23, 24, 25, 26, 27, 28, 0, 0}}}}, //nolint:govet
@@ -131,7 +120,6 @@ var _ = DescribeTable("test vf stats collection", // Collect
131120
"0000:4g:00.0/numa_node": {Data: []byte("0")},
132121
"0000:4g:00.0/class": {Data: []byte("0x020000")},
133122
"0000:4g:00.0/virtfn0": {Data: []byte("/sys/devices/0000:4g:01.0"), Mode: fs.ModeSymlink}},
134-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
135123
netlink.Device{LinkAttrs: netlink.LinkAttrs{Vfs: []netlink.VfInfo{
136124
{0, net.HardwareAddr{}, 0, 0, 0, true, 0, 0, 0, 31, 32, 33, 34, 35, 36, 37, 38, 0, 0}}}}, //nolint:govet
137125
[]metric{
@@ -213,17 +201,9 @@ var _ = DescribeTable("test creating sriovDev collector", // createSriovDevColle
213201
)
214202

215203
var _ = DescribeTable("test getting sriov devices from filesystem", // getSriovDevAddrs
216-
func(fsys fs.FS, driver *drvinfo.DriverInfo, expected []string, logs ...string) {
204+
func(fsys fs.FS, expected []string, logs ...string) {
217205
devfs = fsys
218206

219-
// TODO: replace with ethtool mock
220-
drvinfo.GetDriverInfo = func(name string) (*drvinfo.DriverInfo, error) {
221-
return driver, nil
222-
}
223-
224-
// TODO: replace with fstest.MapFS entry
225-
supportedDrivers = drvinfo.SupportedDrivers{Drivers: drvinfo.DriversList{Drivers: []drvinfo.DriverInfo{*driver}}, DbFilePath: ""}
226-
227207
devs := getSriovDevAddrs()
228208
Expect(devs).To(Equal(expected))
229209

@@ -235,40 +215,38 @@ var _ = DescribeTable("test getting sriov devices from filesystem", // getSriovD
235215
"0000:6f:00.1/sriov_totalvfs": {Data: []byte("64")}, "0000:6f:00.1/class": {Data: []byte("0x020000")},
236216
"0000:7g:00.0/sriov_totalvfs": {Data: []byte("128")}, "0000:7g:00.0/class": {Data: []byte("0x020000")},
237217
"0000:7g:00.1/sriov_totalvfs": {Data: []byte("128")}, "0000:7g:00.1/class": {Data: []byte("0x020000")}},
238-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
239218
[]string{"0000:6f:00.0", "0000:6f:00.1", "0000:7g:00.0", "0000:7g:00.1"}),
240219
Entry("mixed devices",
241220
fstest.MapFS{
242221
"0000:8h:00.0/": {Mode: fs.ModeDir},
243222
"0000:8h:00.1/": {Mode: fs.ModeDir},
244223
"0000:9i:00.0/sriov_totalvfs": {Data: []byte("63")}, "0000:9i:00.0/class": {Data: []byte("0x020000")},
245224
"0000:9i:00.1/sriov_totalvfs": {Data: []byte("63")}, "0000:9i:00.1/class": {Data: []byte("0x020000")}},
246-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
247225
[]string{"0000:9i:00.0", "0000:9i:00.1"}),
248226
Entry("no sriov net devices",
249227
fstest.MapFS{
250228
"0000:1b:00.0/": {Mode: fs.ModeDir},
251229
"0000:1b:00.1/": {Mode: fs.ModeDir},
252230
"0000:1b:00.2/": {Mode: fs.ModeDir},
253231
"0000:1b:00.3/": {Mode: fs.ModeDir}},
254-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
255232
[]string{},
256233
"no sriov net devices found"),
257234
)
258235

259236
var _ = DescribeTable("test getting sriov dev details", // getSriovDev
260-
func(dev string, priority []string, fsys fs.FS, driver *drvinfo.DriverInfo, expected sriovDev, logs ...string) {
237+
func(dev string, priority []string, fsys fs.FS, link netlink.Link, expected sriovDev, logs ...string) {
261238
devfs = fsys
262239
netfs = fsys
263240

264-
// TODO: replace with ethtool mock
265-
drvinfo.GetDriverInfo = func(name string) (*drvinfo.DriverInfo, error) {
266-
return driver, nil
241+
if link != nil {
242+
vfstats.GetLink = func(name string) (netlink.Link, error) {
243+
return link, nil
244+
}
245+
DeferCleanup(func() {
246+
vfstats.GetLink = netlink.LinkByName
247+
})
267248
}
268249

269-
// TODO: replace with fstest.MapFS entry
270-
supportedDrivers = drvinfo.SupportedDrivers{Drivers: drvinfo.DriversList{Drivers: []drvinfo.DriverInfo{*driver}}, DbFilePath: ""}
271-
272250
sriovDev := getSriovDev(dev, priority)
273251
Expect(sriovDev).To(Equal(expected))
274252

@@ -284,7 +262,7 @@ var _ = DescribeTable("test getting sriov dev details", // getSriovDev
284262
"ens785f0/device/sriov": {Mode: fs.ModeDir}, // Added to enable sysfs reader
285263
"0000:5g:00.0/net/ens801f0": {Mode: fs.ModeDir},
286264
"0000:5g:00.0/virtfn0": {Data: []byte("/sys/devices/0000:5g:01.0"), Mode: fs.ModeSymlink}},
287-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
265+
nil,
288266
sriovDev{
289267
"ens785f0",
290268
sysfsReader{"/sys/class/net/%s/device/sriov/%s/stats"},
@@ -299,7 +277,7 @@ var _ = DescribeTable("test getting sriov dev details", // getSriovDev
299277
"0000:6h:00.0/virtfn1": {Data: []byte("/sys/devices/0000:6h:01.1"), Mode: fs.ModeSymlink},
300278
"0000:7i:00.0/net/ens801f0": {Mode: fs.ModeDir},
301279
"0000:7i:00.0/virtfn0": {Data: []byte("/sys/devices/0000:7i:01.0"), Mode: fs.ModeSymlink}},
302-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
280+
&netlink.Device{LinkAttrs: netlink.LinkAttrs{Vfs: []netlink.VfInfo{}}}, //nolint:govet
303281
sriovDev{
304282
"ens785f0",
305283
netlinkReader{vfstats.VfStats("ens785f0")},
@@ -313,7 +291,7 @@ var _ = DescribeTable("test getting sriov dev details", // getSriovDev
313291
"0000:8j:00.0/net/ens785f0": {Mode: fs.ModeDir},
314292
"0000:8j:00.0/virtfn0": {Data: []byte("/sys/devices/0000:8j:01.0"), Mode: fs.ModeSymlink},
315293
"0000:8j:00.0/virtfn1": {Data: []byte("/sys/devices/0000:8j:01.1"), Mode: fs.ModeSymlink}},
316-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
294+
nil,
317295
sriovDev{
318296
"ens785f0",
319297
nil,
@@ -324,7 +302,7 @@ var _ = DescribeTable("test getting sriov dev details", // getSriovDev
324302
[]string{"sysfs"},
325303
fstest.MapFS{
326304
"0000:9k:00.0/net/ens785f0": {Mode: fs.ModeDir}},
327-
&drvinfo.DriverInfo{Name: "ice", Version: "1.9.11"},
305+
nil,
328306
sriovDev{
329307
"ens785f0",
330308
nil,

deployment/daemonset.yaml

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,3 @@
1-
apiVersion: v1
2-
kind: ConfigMap
3-
metadata:
4-
name: sriov-network-metrics-exporter
5-
namespace: monitoring
6-
data:
7-
drivers.yaml: |-
8-
drivers:
9-
- name: ice
10-
version: 1.9.11
11-
- name: mlx5_core
12-
version: 5.15.0-53-generic
13-
---
141
apiVersion: apps/v1
152
kind: DaemonSet
163
metadata:

go.mod

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@ module github.com/k8snetworkplumbingwg/sriov-network-metrics-exporter
33
go 1.18
44

55
require (
6-
github.com/hashicorp/go-version v1.6.0
76
github.com/onsi/ginkgo/v2 v2.5.1
87
github.com/onsi/gomega v1.24.0
98
github.com/prometheus/client_golang v1.12.1
109
github.com/prometheus/client_model v0.2.0
11-
github.com/safchain/ethtool v0.2.0
1210
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852
1311
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8
1412
google.golang.org/grpc v1.56.3
15-
gopkg.in/yaml.v3 v3.0.1
1613
k8s.io/kubelet v0.25.5
1714
)
1815

@@ -32,4 +29,5 @@ require (
3229
golang.org/x/text v0.13.0 // indirect
3330
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
3431
google.golang.org/protobuf v1.33.0 // indirect
32+
gopkg.in/yaml.v3 v3.0.1 // indirect
3533
)

go.sum

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
128128
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
129129
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
130130
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
131-
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
132-
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
133131
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
134132
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
135133
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -193,8 +191,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
193191
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
194192
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
195193
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
196-
github.com/safchain/ethtool v0.2.0 h1:dILxMBqDnQfX192cCAPjZr9v2IgVXeElHPy435Z/IdE=
197-
github.com/safchain/ethtool v0.2.0/go.mod h1:WkKB1DnNtvsMlDmQ50sgwowDJV/hGbJSOvJoEXs1AJQ=
198194
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
199195
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
200196
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
@@ -338,7 +334,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
338334
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
339335
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
340336
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
341-
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
342337
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
343338
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
344339
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

0 commit comments

Comments
 (0)