ethtool.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /*
  2. *
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. *
  20. */
  21. // Package ethtool aims to provide a library giving a simple access to the
  22. // Linux SIOCETHTOOL ioctl operations. It can be used to retrieve informations
  23. // from a network device like statistics, driver related informations or
  24. // even the peer of a VETH interface.
  25. package ethtool
  26. import (
  27. "bytes"
  28. "encoding/hex"
  29. "fmt"
  30. "strings"
  31. "unsafe"
  32. "golang.org/x/sys/unix"
  33. )
  34. // Maximum size of an interface name
  35. const (
  36. IFNAMSIZ = 16
  37. )
  38. // ioctl ethtool request
  39. const (
  40. SIOCETHTOOL = 0x8946
  41. )
  42. // ethtool stats related constants.
  43. const (
  44. ETH_GSTRING_LEN = 32
  45. ETH_SS_STATS = 1
  46. ETH_SS_FEATURES = 4
  47. ETHTOOL_GDRVINFO = 0x00000003
  48. ETHTOOL_GSTRINGS = 0x0000001b
  49. ETHTOOL_GSTATS = 0x0000001d
  50. // other CMDs from ethtool-copy.h of ethtool-3.5 package
  51. ETHTOOL_GSET = 0x00000001 /* Get settings. */
  52. ETHTOOL_SSET = 0x00000002 /* Set settings. */
  53. ETHTOOL_GMSGLVL = 0x00000007 /* Get driver message level */
  54. ETHTOOL_SMSGLVL = 0x00000008 /* Set driver msg level. */
  55. ETHTOOL_GCHANNELS = 0x0000003c /* Get no of channels */
  56. ETHTOOL_SCHANNELS = 0x0000003d /* Set no of channels */
  57. ETHTOOL_GCOALESCE = 0x0000000e /* Get coalesce config */
  58. /* Get link status for host, i.e. whether the interface *and* the
  59. * physical port (if there is one) are up (ethtool_value). */
  60. ETHTOOL_GLINK = 0x0000000a
  61. ETHTOOL_GMODULEINFO = 0x00000042 /* Get plug-in module information */
  62. ETHTOOL_GMODULEEEPROM = 0x00000043 /* Get plug-in module eeprom */
  63. ETHTOOL_GPERMADDR = 0x00000020
  64. ETHTOOL_GFEATURES = 0x0000003a /* Get device offload settings */
  65. ETHTOOL_SFEATURES = 0x0000003b /* Change device offload settings */
  66. ETHTOOL_GFLAGS = 0x00000025 /* Get flags bitmap(ethtool_value) */
  67. ETHTOOL_GSSET_INFO = 0x00000037 /* Get string set info */
  68. )
  69. // MAX_GSTRINGS maximum number of stats entries that ethtool can
  70. // retrieve currently.
  71. const (
  72. MAX_GSTRINGS = 16384
  73. MAX_FEATURE_BLOCKS = (MAX_GSTRINGS + 32 - 1) / 32
  74. EEPROM_LEN = 640
  75. PERMADDR_LEN = 32
  76. )
  77. type ifreq struct {
  78. ifr_name [IFNAMSIZ]byte
  79. ifr_data uintptr
  80. }
  81. // following structures comes from uapi/linux/ethtool.h
  82. type ethtoolSsetInfo struct {
  83. cmd uint32
  84. reserved uint32
  85. sset_mask uint32
  86. data uintptr
  87. }
  88. type ethtoolGetFeaturesBlock struct {
  89. available uint32
  90. requested uint32
  91. active uint32
  92. never_changed uint32
  93. }
  94. type ethtoolGfeatures struct {
  95. cmd uint32
  96. size uint32
  97. blocks [MAX_FEATURE_BLOCKS]ethtoolGetFeaturesBlock
  98. }
  99. type ethtoolSetFeaturesBlock struct {
  100. valid uint32
  101. requested uint32
  102. }
  103. type ethtoolSfeatures struct {
  104. cmd uint32
  105. size uint32
  106. blocks [MAX_FEATURE_BLOCKS]ethtoolSetFeaturesBlock
  107. }
  108. type ethtoolDrvInfo struct {
  109. cmd uint32
  110. driver [32]byte
  111. version [32]byte
  112. fw_version [32]byte
  113. bus_info [32]byte
  114. erom_version [32]byte
  115. reserved2 [12]byte
  116. n_priv_flags uint32
  117. n_stats uint32
  118. testinfo_len uint32
  119. eedump_len uint32
  120. regdump_len uint32
  121. }
  122. // DrvInfo contains driver information
  123. // ethtool.h v3.5: struct ethtool_drvinfo
  124. type DrvInfo struct {
  125. Cmd uint32
  126. Driver string
  127. Version string
  128. FwVersion string
  129. BusInfo string
  130. EromVersion string
  131. Reserved2 string
  132. NPrivFlags uint32
  133. NStats uint32
  134. TestInfoLen uint32
  135. EedumpLen uint32
  136. RegdumpLen uint32
  137. }
  138. // Channels contains the number of channels for a given interface.
  139. type Channels struct {
  140. Cmd uint32
  141. MaxRx uint32
  142. MaxTx uint32
  143. MaxOther uint32
  144. MaxCombined uint32
  145. RxCount uint32
  146. TxCount uint32
  147. OtherCount uint32
  148. CombinedCount uint32
  149. }
  150. // Coalesce is a coalesce config for an interface
  151. type Coalesce struct {
  152. Cmd uint32
  153. RxCoalesceUsecs uint32
  154. RxMaxCoalescedFrames uint32
  155. RxCoalesceUsecsIrq uint32
  156. RxMaxCoalescedFramesIrq uint32
  157. TxCoalesceUsecs uint32
  158. TxMaxCoalescedFrames uint32
  159. TxCoalesceUsecsIrq uint32
  160. TxMaxCoalescedFramesIrq uint32
  161. StatsBlockCoalesceUsecs uint32
  162. UseAdaptiveRxCoalesce uint32
  163. UseAdaptiveTxCoalesce uint32
  164. PktRateLow uint32
  165. RxCoalesceUsecsLow uint32
  166. RxMaxCoalescedFramesLow uint32
  167. TxCoalesceUsecsLow uint32
  168. TxMaxCoalescedFramesLow uint32
  169. PktRateHigh uint32
  170. RxCoalesceUsecsHigh uint32
  171. RxMaxCoalescedFramesHigh uint32
  172. TxCoalesceUsecsHigh uint32
  173. TxMaxCoalescedFramesHigh uint32
  174. RateSampleInterval uint32
  175. }
  176. type ethtoolGStrings struct {
  177. cmd uint32
  178. string_set uint32
  179. len uint32
  180. data [MAX_GSTRINGS * ETH_GSTRING_LEN]byte
  181. }
  182. type ethtoolStats struct {
  183. cmd uint32
  184. n_stats uint32
  185. data [MAX_GSTRINGS]uint64
  186. }
  187. type ethtoolEeprom struct {
  188. cmd uint32
  189. magic uint32
  190. offset uint32
  191. len uint32
  192. data [EEPROM_LEN]byte
  193. }
  194. type ethtoolModInfo struct {
  195. cmd uint32
  196. tpe uint32
  197. eeprom_len uint32
  198. reserved [8]uint32
  199. }
  200. type ethtoolLink struct {
  201. cmd uint32
  202. data uint32
  203. }
  204. type ethtoolPermAddr struct {
  205. cmd uint32
  206. size uint32
  207. data [PERMADDR_LEN]byte
  208. }
  209. type Ethtool struct {
  210. fd int
  211. }
  212. // DriverName returns the driver name of the given interface name.
  213. func (e *Ethtool) DriverName(intf string) (string, error) {
  214. info, err := e.getDriverInfo(intf)
  215. if err != nil {
  216. return "", err
  217. }
  218. return string(bytes.Trim(info.driver[:], "\x00")), nil
  219. }
  220. // BusInfo returns the bus information of the given interface name.
  221. func (e *Ethtool) BusInfo(intf string) (string, error) {
  222. info, err := e.getDriverInfo(intf)
  223. if err != nil {
  224. return "", err
  225. }
  226. return string(bytes.Trim(info.bus_info[:], "\x00")), nil
  227. }
  228. // ModuleEeprom returns Eeprom information of the given interface name.
  229. func (e *Ethtool) ModuleEeprom(intf string) ([]byte, error) {
  230. eeprom, _, err := e.getModuleEeprom(intf)
  231. if err != nil {
  232. return nil, err
  233. }
  234. return eeprom.data[:eeprom.len], nil
  235. }
  236. // ModuleEeprom returns Eeprom information of the given interface name.
  237. func (e *Ethtool) ModuleEepromHex(intf string) (string, error) {
  238. eeprom, _, err := e.getModuleEeprom(intf)
  239. if err != nil {
  240. return "", err
  241. }
  242. return hex.EncodeToString(eeprom.data[:eeprom.len]), nil
  243. }
  244. // DriverInfo returns driver information of the given interface name.
  245. func (e *Ethtool) DriverInfo(intf string) (DrvInfo, error) {
  246. i, err := e.getDriverInfo(intf)
  247. if err != nil {
  248. return DrvInfo{}, err
  249. }
  250. drvInfo := DrvInfo{
  251. Cmd: i.cmd,
  252. Driver: string(bytes.Trim(i.driver[:], "\x00")),
  253. Version: string(bytes.Trim(i.version[:], "\x00")),
  254. FwVersion: string(bytes.Trim(i.fw_version[:], "\x00")),
  255. BusInfo: string(bytes.Trim(i.bus_info[:], "\x00")),
  256. EromVersion: string(bytes.Trim(i.erom_version[:], "\x00")),
  257. Reserved2: string(bytes.Trim(i.reserved2[:], "\x00")),
  258. NPrivFlags: i.n_priv_flags,
  259. NStats: i.n_stats,
  260. TestInfoLen: i.testinfo_len,
  261. EedumpLen: i.eedump_len,
  262. RegdumpLen: i.regdump_len,
  263. }
  264. return drvInfo, nil
  265. }
  266. // GetChannels returns the number of channels for the given interface name.
  267. func (e *Ethtool) GetChannels(intf string) (Channels, error) {
  268. channels, err := e.getChannels(intf)
  269. if err != nil {
  270. return Channels{}, err
  271. }
  272. return channels, nil
  273. }
  274. // SetChannels sets the number of channels for the given interface name and
  275. // returns the new number of channels.
  276. func (e *Ethtool) SetChannels(intf string, channels Channels) (Channels, error) {
  277. channels, err := e.setChannels(intf, channels)
  278. if err != nil {
  279. return Channels{}, err
  280. }
  281. return channels, nil
  282. }
  283. // GetCoalesce returns the coalesce config for the given interface name.
  284. func (e *Ethtool) GetCoalesce(intf string) (Coalesce, error) {
  285. coalesce, err := e.getCoalesce(intf)
  286. if err != nil {
  287. return Coalesce{}, err
  288. }
  289. return coalesce, nil
  290. }
  291. // PermAddr returns permanent address of the given interface name.
  292. func (e *Ethtool) PermAddr(intf string) (string, error) {
  293. permAddr, err := e.getPermAddr(intf)
  294. if err != nil {
  295. return "", err
  296. }
  297. if permAddr.data[0] == 0 && permAddr.data[1] == 0 &&
  298. permAddr.data[2] == 0 && permAddr.data[3] == 0 &&
  299. permAddr.data[4] == 0 && permAddr.data[5] == 0 {
  300. return "", nil
  301. }
  302. return fmt.Sprintf("%x:%x:%x:%x:%x:%x",
  303. permAddr.data[0:1],
  304. permAddr.data[1:2],
  305. permAddr.data[2:3],
  306. permAddr.data[3:4],
  307. permAddr.data[4:5],
  308. permAddr.data[5:6],
  309. ), nil
  310. }
  311. func (e *Ethtool) ioctl(intf string, data uintptr) error {
  312. var name [IFNAMSIZ]byte
  313. copy(name[:], []byte(intf))
  314. ifr := ifreq{
  315. ifr_name: name,
  316. ifr_data: data,
  317. }
  318. _, _, ep := unix.Syscall(unix.SYS_IOCTL, uintptr(e.fd), SIOCETHTOOL, uintptr(unsafe.Pointer(&ifr)))
  319. if ep != 0 {
  320. return ep
  321. }
  322. return nil
  323. }
  324. func (e *Ethtool) getDriverInfo(intf string) (ethtoolDrvInfo, error) {
  325. drvinfo := ethtoolDrvInfo{
  326. cmd: ETHTOOL_GDRVINFO,
  327. }
  328. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&drvinfo))); err != nil {
  329. return ethtoolDrvInfo{}, err
  330. }
  331. return drvinfo, nil
  332. }
  333. func (e *Ethtool) getChannels(intf string) (Channels, error) {
  334. channels := Channels{
  335. Cmd: ETHTOOL_GCHANNELS,
  336. }
  337. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&channels))); err != nil {
  338. return Channels{}, err
  339. }
  340. return channels, nil
  341. }
  342. func (e *Ethtool) setChannels(intf string, channels Channels) (Channels, error) {
  343. channels.Cmd = ETHTOOL_SCHANNELS
  344. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&channels))); err != nil {
  345. return Channels{}, err
  346. }
  347. return channels, nil
  348. }
  349. func (e *Ethtool) getCoalesce(intf string) (Coalesce, error) {
  350. coalesce := Coalesce{
  351. Cmd: ETHTOOL_GCOALESCE,
  352. }
  353. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&coalesce))); err != nil {
  354. return Coalesce{}, err
  355. }
  356. return coalesce, nil
  357. }
  358. func (e *Ethtool) getPermAddr(intf string) (ethtoolPermAddr, error) {
  359. permAddr := ethtoolPermAddr{
  360. cmd: ETHTOOL_GPERMADDR,
  361. size: PERMADDR_LEN,
  362. }
  363. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&permAddr))); err != nil {
  364. return ethtoolPermAddr{}, err
  365. }
  366. return permAddr, nil
  367. }
  368. func (e *Ethtool) getModuleEeprom(intf string) (ethtoolEeprom, ethtoolModInfo, error) {
  369. modInfo := ethtoolModInfo{
  370. cmd: ETHTOOL_GMODULEINFO,
  371. }
  372. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&modInfo))); err != nil {
  373. return ethtoolEeprom{}, ethtoolModInfo{}, err
  374. }
  375. eeprom := ethtoolEeprom{
  376. cmd: ETHTOOL_GMODULEEEPROM,
  377. len: modInfo.eeprom_len,
  378. offset: 0,
  379. }
  380. if modInfo.eeprom_len > EEPROM_LEN {
  381. return ethtoolEeprom{}, ethtoolModInfo{}, fmt.Errorf("eeprom size: %d is larger than buffer size: %d", modInfo.eeprom_len, EEPROM_LEN)
  382. }
  383. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&eeprom))); err != nil {
  384. return ethtoolEeprom{}, ethtoolModInfo{}, err
  385. }
  386. return eeprom, modInfo, nil
  387. }
  388. func isFeatureBitSet(blocks [MAX_FEATURE_BLOCKS]ethtoolGetFeaturesBlock, index uint) bool {
  389. return (blocks)[index/32].active&(1<<(index%32)) != 0
  390. }
  391. func setFeatureBit(blocks *[MAX_FEATURE_BLOCKS]ethtoolSetFeaturesBlock, index uint, value bool) {
  392. blockIndex, bitIndex := index/32, index%32
  393. blocks[blockIndex].valid |= 1 << bitIndex
  394. if value {
  395. blocks[blockIndex].requested |= 1 << bitIndex
  396. } else {
  397. blocks[blockIndex].requested &= ^(1 << bitIndex)
  398. }
  399. }
  400. // FeatureNames shows supported features by their name.
  401. func (e *Ethtool) FeatureNames(intf string) (map[string]uint, error) {
  402. ssetInfo := ethtoolSsetInfo{
  403. cmd: ETHTOOL_GSSET_INFO,
  404. sset_mask: 1 << ETH_SS_FEATURES,
  405. }
  406. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&ssetInfo))); err != nil {
  407. return nil, err
  408. }
  409. length := uint32(ssetInfo.data)
  410. if length == 0 {
  411. return map[string]uint{}, nil
  412. } else if length > MAX_GSTRINGS {
  413. return nil, fmt.Errorf("ethtool currently doesn't support more than %d entries, received %d", MAX_GSTRINGS, length)
  414. }
  415. gstrings := ethtoolGStrings{
  416. cmd: ETHTOOL_GSTRINGS,
  417. string_set: ETH_SS_FEATURES,
  418. len: length,
  419. data: [MAX_GSTRINGS * ETH_GSTRING_LEN]byte{},
  420. }
  421. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&gstrings))); err != nil {
  422. return nil, err
  423. }
  424. var result = make(map[string]uint)
  425. for i := 0; i != int(length); i++ {
  426. b := gstrings.data[i*ETH_GSTRING_LEN : i*ETH_GSTRING_LEN+ETH_GSTRING_LEN]
  427. key := string(bytes.Trim(b, "\x00"))
  428. if key != "" {
  429. result[key] = uint(i)
  430. }
  431. }
  432. return result, nil
  433. }
  434. // Features retrieves features of the given interface name.
  435. func (e *Ethtool) Features(intf string) (map[string]bool, error) {
  436. names, err := e.FeatureNames(intf)
  437. if err != nil {
  438. return nil, err
  439. }
  440. length := uint32(len(names))
  441. if length == 0 {
  442. return map[string]bool{}, nil
  443. }
  444. features := ethtoolGfeatures{
  445. cmd: ETHTOOL_GFEATURES,
  446. size: (length + 32 - 1) / 32,
  447. }
  448. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&features))); err != nil {
  449. return nil, err
  450. }
  451. var result = make(map[string]bool, length)
  452. for key, index := range names {
  453. result[key] = isFeatureBitSet(features.blocks, index)
  454. }
  455. return result, nil
  456. }
  457. // Change requests a change in the given device's features.
  458. func (e *Ethtool) Change(intf string, config map[string]bool) error {
  459. names, err := e.FeatureNames(intf)
  460. if err != nil {
  461. return err
  462. }
  463. length := uint32(len(names))
  464. features := ethtoolSfeatures{
  465. cmd: ETHTOOL_SFEATURES,
  466. size: (length + 32 - 1) / 32,
  467. }
  468. for key, value := range config {
  469. if index, ok := names[key]; ok {
  470. setFeatureBit(&features.blocks, index, value)
  471. } else {
  472. return fmt.Errorf("unsupported feature %q", key)
  473. }
  474. }
  475. return e.ioctl(intf, uintptr(unsafe.Pointer(&features)))
  476. }
  477. // Get state of a link.
  478. func (e *Ethtool) LinkState(intf string) (uint32, error) {
  479. x := ethtoolLink{
  480. cmd: ETHTOOL_GLINK,
  481. }
  482. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&x))); err != nil {
  483. return 0, err
  484. }
  485. return x.data, nil
  486. }
  487. // Stats retrieves stats of the given interface name.
  488. func (e *Ethtool) Stats(intf string) (map[string]uint64, error) {
  489. drvinfo := ethtoolDrvInfo{
  490. cmd: ETHTOOL_GDRVINFO,
  491. }
  492. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&drvinfo))); err != nil {
  493. return nil, err
  494. }
  495. if drvinfo.n_stats*ETH_GSTRING_LEN > MAX_GSTRINGS*ETH_GSTRING_LEN {
  496. return nil, fmt.Errorf("ethtool currently doesn't support more than %d entries, received %d", MAX_GSTRINGS, drvinfo.n_stats)
  497. }
  498. gstrings := ethtoolGStrings{
  499. cmd: ETHTOOL_GSTRINGS,
  500. string_set: ETH_SS_STATS,
  501. len: drvinfo.n_stats,
  502. data: [MAX_GSTRINGS * ETH_GSTRING_LEN]byte{},
  503. }
  504. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&gstrings))); err != nil {
  505. return nil, err
  506. }
  507. stats := ethtoolStats{
  508. cmd: ETHTOOL_GSTATS,
  509. n_stats: drvinfo.n_stats,
  510. data: [MAX_GSTRINGS]uint64{},
  511. }
  512. if err := e.ioctl(intf, uintptr(unsafe.Pointer(&stats))); err != nil {
  513. return nil, err
  514. }
  515. var result = make(map[string]uint64)
  516. for i := 0; i != int(drvinfo.n_stats); i++ {
  517. b := gstrings.data[i*ETH_GSTRING_LEN : i*ETH_GSTRING_LEN+ETH_GSTRING_LEN]
  518. strEnd := strings.Index(string(b), "\x00")
  519. if strEnd == -1 {
  520. strEnd = ETH_GSTRING_LEN
  521. }
  522. key := string(b[:strEnd])
  523. if len(key) != 0 {
  524. result[key] = stats.data[i]
  525. }
  526. }
  527. return result, nil
  528. }
  529. // Close closes the ethool handler
  530. func (e *Ethtool) Close() {
  531. unix.Close(e.fd)
  532. }
  533. // NewEthtool returns a new ethtool handler
  534. func NewEthtool() (*Ethtool, error) {
  535. fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
  536. if err != nil {
  537. return nil, err
  538. }
  539. return &Ethtool{
  540. fd: int(fd),
  541. }, nil
  542. }
  543. // BusInfo returns bus information of the given interface name.
  544. func BusInfo(intf string) (string, error) {
  545. e, err := NewEthtool()
  546. if err != nil {
  547. return "", err
  548. }
  549. defer e.Close()
  550. return e.BusInfo(intf)
  551. }
  552. // DriverName returns the driver name of the given interface name.
  553. func DriverName(intf string) (string, error) {
  554. e, err := NewEthtool()
  555. if err != nil {
  556. return "", err
  557. }
  558. defer e.Close()
  559. return e.DriverName(intf)
  560. }
  561. // Stats retrieves stats of the given interface name.
  562. func Stats(intf string) (map[string]uint64, error) {
  563. e, err := NewEthtool()
  564. if err != nil {
  565. return nil, err
  566. }
  567. defer e.Close()
  568. return e.Stats(intf)
  569. }
  570. // PermAddr returns permanent address of the given interface name.
  571. func PermAddr(intf string) (string, error) {
  572. e, err := NewEthtool()
  573. if err != nil {
  574. return "", err
  575. }
  576. defer e.Close()
  577. return e.PermAddr(intf)
  578. }