link.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. package rtnetlink
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "github.com/jsimonetti/rtnetlink/internal/unix"
  7. "github.com/mdlayher/netlink"
  8. )
  9. var (
  10. // errInvalidLinkMessage is returned when a LinkMessage is malformed.
  11. errInvalidLinkMessage = errors.New("rtnetlink LinkMessage is invalid or too short")
  12. // errInvalidLinkMessageAttr is returned when link attributes are malformed.
  13. errInvalidLinkMessageAttr = errors.New("rtnetlink LinkMessage has a wrong attribute data length")
  14. )
  15. var _ Message = &LinkMessage{}
  16. // A LinkMessage is a route netlink link message.
  17. type LinkMessage struct {
  18. // Always set to AF_UNSPEC (0)
  19. Family uint16
  20. // Device Type
  21. Type uint16
  22. // Unique interface index, using a nonzero value with
  23. // NewLink will instruct the kernel to create a
  24. // device with the given index (kernel 3.7+ required)
  25. Index uint32
  26. // Contains device flags, see netdevice(7)
  27. Flags uint32
  28. // Change Flags, specifies which flags will be affected by the Flags field
  29. Change uint32
  30. // Attributes List
  31. Attributes *LinkAttributes
  32. }
  33. // MarshalBinary marshals a LinkMessage into a byte slice.
  34. func (m *LinkMessage) MarshalBinary() ([]byte, error) {
  35. b := make([]byte, unix.SizeofIfInfomsg)
  36. b[0] = 0 // Family
  37. b[1] = 0 // reserved
  38. nativeEndian.PutUint16(b[2:4], m.Type)
  39. nativeEndian.PutUint32(b[4:8], m.Index)
  40. nativeEndian.PutUint32(b[8:12], m.Flags)
  41. nativeEndian.PutUint32(b[12:16], m.Change)
  42. if m.Attributes != nil {
  43. ae := netlink.NewAttributeEncoder()
  44. ae.ByteOrder = nativeEndian
  45. err := m.Attributes.encode(ae)
  46. if err != nil {
  47. return nil, err
  48. }
  49. a, err := ae.Encode()
  50. if err != nil {
  51. return nil, err
  52. }
  53. return append(b, a...), nil
  54. }
  55. return b, nil
  56. }
  57. // UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
  58. func (m *LinkMessage) UnmarshalBinary(b []byte) error {
  59. l := len(b)
  60. if l < unix.SizeofIfInfomsg {
  61. return errInvalidLinkMessage
  62. }
  63. m.Family = nativeEndian.Uint16(b[0:2])
  64. m.Type = nativeEndian.Uint16(b[2:4])
  65. m.Index = nativeEndian.Uint32(b[4:8])
  66. m.Flags = nativeEndian.Uint32(b[8:12])
  67. m.Change = nativeEndian.Uint32(b[12:16])
  68. if l > unix.SizeofIfInfomsg {
  69. m.Attributes = &LinkAttributes{}
  70. ad, err := netlink.NewAttributeDecoder(b[16:])
  71. if err != nil {
  72. return err
  73. }
  74. ad.ByteOrder = nativeEndian
  75. err = m.Attributes.decode(ad)
  76. if err != nil {
  77. return err
  78. }
  79. }
  80. return nil
  81. }
  82. // rtMessage is an empty method to sattisfy the Message interface.
  83. func (*LinkMessage) rtMessage() {}
  84. // LinkService is used to retrieve rtnetlink family information.
  85. type LinkService struct {
  86. c *Conn
  87. }
  88. // execute executes the request and returns the messages as a LinkMessage slice
  89. func (l *LinkService) execute(m Message, family uint16, flags netlink.HeaderFlags) ([]LinkMessage, error) {
  90. msgs, err := l.c.Execute(m, family, flags)
  91. links := make([]LinkMessage, len(msgs))
  92. for i := range msgs {
  93. links[i] = *msgs[i].(*LinkMessage)
  94. }
  95. return links, err
  96. }
  97. // New creates a new interface using the LinkMessage information.
  98. func (l *LinkService) New(req *LinkMessage) error {
  99. flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
  100. _, err := l.execute(req, unix.RTM_NEWLINK, flags)
  101. return err
  102. }
  103. // Delete removes an interface by index.
  104. func (l *LinkService) Delete(index uint32) error {
  105. req := &LinkMessage{
  106. Index: index,
  107. }
  108. flags := netlink.Request | netlink.Acknowledge
  109. _, err := l.c.Execute(req, unix.RTM_DELLINK, flags)
  110. return err
  111. }
  112. // Get retrieves interface information by index.
  113. func (l *LinkService) Get(index uint32) (LinkMessage, error) {
  114. req := &LinkMessage{
  115. Index: index,
  116. }
  117. flags := netlink.Request | netlink.DumpFiltered
  118. links, err := l.execute(req, unix.RTM_GETLINK, flags)
  119. if len(links) != 1 {
  120. return LinkMessage{}, fmt.Errorf("too many/little matches, expected 1, actual %d", len(links))
  121. }
  122. return links[0], err
  123. }
  124. // Set sets interface attributes according to the LinkMessage information.
  125. //
  126. // ref: https://lwn.net/Articles/236919/
  127. // We explicitly use RTM_NEWLINK to set link attributes instead of
  128. // RTM_SETLINK because:
  129. // - using RTM_SETLINK is actually an old rtnetlink API, not supporting most
  130. // attributes common today
  131. // - using RTM_NEWLINK is the prefered way to create AND update links
  132. // - RTM_NEWLINK is backward compatible to RTM_SETLINK
  133. func (l *LinkService) Set(req *LinkMessage) error {
  134. flags := netlink.Request | netlink.Acknowledge
  135. _, err := l.c.Execute(req, unix.RTM_NEWLINK, flags)
  136. return err
  137. }
  138. func (l *LinkService) list(kind string) ([]LinkMessage, error) {
  139. req := &LinkMessage{}
  140. if kind != "" {
  141. req.Attributes = &LinkAttributes{
  142. Info: &LinkInfo{Kind: kind},
  143. }
  144. }
  145. flags := netlink.Request | netlink.Dump
  146. return l.execute(req, unix.RTM_GETLINK, flags)
  147. }
  148. // ListByKind retrieves all interfaces of a specific kind.
  149. func (l *LinkService) ListByKind(kind string) ([]LinkMessage, error) {
  150. return l.list(kind)
  151. }
  152. // List retrieves all interfaces.
  153. func (l *LinkService) List() ([]LinkMessage, error) {
  154. return l.list("")
  155. }
  156. // LinkAttributes contains all attributes for an interface.
  157. type LinkAttributes struct {
  158. Address net.HardwareAddr // Interface L2 address
  159. Alias *string // Interface alias name
  160. Broadcast net.HardwareAddr // L2 broadcast address
  161. Carrier *uint8 // Current physical link state of the interface.
  162. CarrierChanges *uint32 // Number of times the link has seen a change from UP to DOWN and vice versa
  163. CarrierUpCount *uint32 // Number of times the link has been up
  164. CarrierDownCount *uint32 // Number of times the link has been down
  165. Index *uint32 // System-wide interface unique index identifier
  166. Info *LinkInfo // Detailed Interface Information
  167. LinkMode *uint8 // Interface link mode
  168. MTU uint32 // MTU of the device
  169. Name string // Device name
  170. NetDevGroup *uint32 // Interface network device group
  171. OperationalState OperationalState // Interface operation state
  172. PhysPortID *string // Interface unique physical port identifier within the NIC
  173. PhysPortName *string // Interface physical port name within the NIC
  174. PhysSwitchID *string // Unique physical switch identifier of a switch this port belongs to
  175. QueueDisc string // Queueing discipline
  176. Master *uint32 // Master device index (0 value un-enslaves)
  177. Stats *LinkStats // Interface Statistics
  178. Stats64 *LinkStats64 // Interface Statistics (64 bits version)
  179. TxQueueLen *uint32 // Interface transmit queue len in number of packets
  180. Type uint32 // Link type
  181. XDP *LinkXDP // Express Data Patch Information
  182. }
  183. // OperationalState represents an interface's operational state.
  184. type OperationalState uint8
  185. // Constants that represent operational state of an interface
  186. //
  187. // Adapted from https://elixir.bootlin.com/linux/v4.19.2/source/include/uapi/linux/if.h#L166
  188. const (
  189. OperStateUnknown OperationalState = iota // status could not be determined
  190. OperStateNotPresent // down, due to some missing component (typically hardware)
  191. OperStateDown // down, either administratively or due to a fault
  192. OperStateLowerLayerDown // down, due to lower-layer interfaces
  193. OperStateTesting // operationally down, in some test mode
  194. OperStateDormant // down, waiting for some external event
  195. OperStateUp // interface is in a state to send and receive packets
  196. )
  197. // unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
  198. func (a *LinkAttributes) decode(ad *netlink.AttributeDecoder) error {
  199. for ad.Next() {
  200. switch ad.Type() {
  201. case unix.IFLA_UNSPEC:
  202. // unused attribute
  203. case unix.IFLA_ADDRESS:
  204. l := len(ad.Bytes())
  205. if l < 4 || l > 32 {
  206. return errInvalidLinkMessageAttr
  207. }
  208. a.Address = ad.Bytes()
  209. case unix.IFLA_IFALIAS:
  210. v := ad.String()
  211. a.Alias = &v
  212. case unix.IFLA_BROADCAST:
  213. l := len(ad.Bytes())
  214. if l < 4 || l > 32 {
  215. return errInvalidLinkMessageAttr
  216. }
  217. a.Broadcast = ad.Bytes()
  218. case unix.IFLA_CARRIER:
  219. v := ad.Uint8()
  220. a.Carrier = &v
  221. case unix.IFLA_CARRIER_CHANGES:
  222. v := ad.Uint32()
  223. a.CarrierChanges = &v
  224. case unix.IFLA_CARRIER_UP_COUNT:
  225. v := ad.Uint32()
  226. a.CarrierUpCount = &v
  227. case unix.IFLA_CARRIER_DOWN_COUNT:
  228. v := ad.Uint32()
  229. a.CarrierDownCount = &v
  230. case unix.IFLA_GROUP:
  231. v := ad.Uint32()
  232. a.NetDevGroup = &v
  233. case unix.IFLA_MTU:
  234. a.MTU = ad.Uint32()
  235. case unix.IFLA_IFNAME:
  236. a.Name = ad.String()
  237. case unix.IFLA_LINK:
  238. a.Type = ad.Uint32()
  239. case unix.IFLA_LINKINFO:
  240. a.Info = &LinkInfo{}
  241. ad.Nested(a.Info.decode)
  242. case unix.IFLA_LINKMODE:
  243. v := ad.Uint8()
  244. a.LinkMode = &v
  245. case unix.IFLA_MASTER:
  246. v := ad.Uint32()
  247. a.Master = &v
  248. case unix.IFLA_OPERSTATE:
  249. a.OperationalState = OperationalState(ad.Uint8())
  250. case unix.IFLA_PHYS_PORT_ID:
  251. v := ad.String()
  252. a.PhysPortID = &v
  253. case unix.IFLA_PHYS_SWITCH_ID:
  254. v := ad.String()
  255. a.PhysSwitchID = &v
  256. case unix.IFLA_PHYS_PORT_NAME:
  257. v := ad.String()
  258. a.PhysPortName = &v
  259. case unix.IFLA_QDISC:
  260. a.QueueDisc = ad.String()
  261. case unix.IFLA_STATS:
  262. a.Stats = &LinkStats{}
  263. err := a.Stats.unmarshalBinary(ad.Bytes())
  264. if err != nil {
  265. return err
  266. }
  267. case unix.IFLA_STATS64:
  268. a.Stats64 = &LinkStats64{}
  269. err := a.Stats64.unmarshalBinary(ad.Bytes())
  270. if err != nil {
  271. return err
  272. }
  273. case unix.IFLA_TXQLEN:
  274. v := ad.Uint32()
  275. a.TxQueueLen = &v
  276. case unix.IFLA_XDP:
  277. a.XDP = &LinkXDP{}
  278. ad.Nested(a.XDP.decode)
  279. }
  280. }
  281. return nil
  282. }
  283. // MarshalBinary marshals a LinkAttributes into a byte slice.
  284. func (a *LinkAttributes) encode(ae *netlink.AttributeEncoder) error {
  285. ae.Uint16(unix.IFLA_UNSPEC, 0)
  286. ae.String(unix.IFLA_IFNAME, a.Name)
  287. ae.Uint32(unix.IFLA_LINK, a.Type)
  288. ae.String(unix.IFLA_QDISC, a.QueueDisc)
  289. if a.MTU != 0 {
  290. ae.Uint32(unix.IFLA_MTU, a.MTU)
  291. }
  292. if len(a.Address) != 0 {
  293. ae.Bytes(unix.IFLA_ADDRESS, a.Address)
  294. }
  295. if len(a.Broadcast) != 0 {
  296. ae.Bytes(unix.IFLA_BROADCAST, a.Broadcast)
  297. }
  298. if a.OperationalState != OperStateUnknown {
  299. ae.Uint8(unix.IFLA_OPERSTATE, uint8(a.OperationalState))
  300. }
  301. if a.Info != nil {
  302. nae := netlink.NewAttributeEncoder()
  303. nae.ByteOrder = ae.ByteOrder
  304. err := a.Info.encode(nae)
  305. if err != nil {
  306. return err
  307. }
  308. b, err := nae.Encode()
  309. if err != nil {
  310. return err
  311. }
  312. ae.Bytes(unix.IFLA_LINKINFO, b)
  313. }
  314. if a.XDP != nil {
  315. nae := netlink.NewAttributeEncoder()
  316. nae.ByteOrder = ae.ByteOrder
  317. err := a.XDP.encode(nae)
  318. if err != nil {
  319. return err
  320. }
  321. b, err := nae.Encode()
  322. if err != nil {
  323. return err
  324. }
  325. ae.Bytes(unix.IFLA_XDP, b)
  326. }
  327. if a.Master != nil {
  328. ae.Uint32(unix.IFLA_MASTER, *a.Master)
  329. }
  330. return nil
  331. }
  332. // LinkStats contains packet statistics
  333. type LinkStats struct {
  334. RXPackets uint32 // total packets received
  335. TXPackets uint32 // total packets transmitted
  336. RXBytes uint32 // total bytes received
  337. TXBytes uint32 // total bytes transmitted
  338. RXErrors uint32 // bad packets received
  339. TXErrors uint32 // packet transmit problems
  340. RXDropped uint32 // no space in linux buffers
  341. TXDropped uint32 // no space available in linux
  342. Multicast uint32 // multicast packets received
  343. Collisions uint32
  344. // detailed rx_errors:
  345. RXLengthErrors uint32
  346. RXOverErrors uint32 // receiver ring buff overflow
  347. RXCRCErrors uint32 // recved pkt with crc error
  348. RXFrameErrors uint32 // recv'd frame alignment error
  349. RXFIFOErrors uint32 // recv'r fifo overrun
  350. RXMissedErrors uint32 // receiver missed packet
  351. // detailed tx_errors
  352. TXAbortedErrors uint32
  353. TXCarrierErrors uint32
  354. TXFIFOErrors uint32
  355. TXHeartbeatErrors uint32
  356. TXWindowErrors uint32
  357. // for cslip etc
  358. RXCompressed uint32
  359. TXCompressed uint32
  360. RXNoHandler uint32 // dropped, no handler found
  361. }
  362. // unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
  363. func (a *LinkStats) unmarshalBinary(b []byte) error {
  364. l := len(b)
  365. if l != 92 && l != 96 {
  366. return fmt.Errorf("incorrect LinkMessage size, want: 92 or 96, got: %d", len(b))
  367. }
  368. a.RXPackets = nativeEndian.Uint32(b[0:4])
  369. a.TXPackets = nativeEndian.Uint32(b[4:8])
  370. a.RXBytes = nativeEndian.Uint32(b[8:12])
  371. a.TXBytes = nativeEndian.Uint32(b[12:16])
  372. a.RXErrors = nativeEndian.Uint32(b[16:20])
  373. a.TXErrors = nativeEndian.Uint32(b[20:24])
  374. a.RXDropped = nativeEndian.Uint32(b[24:28])
  375. a.TXDropped = nativeEndian.Uint32(b[28:32])
  376. a.Multicast = nativeEndian.Uint32(b[32:36])
  377. a.Collisions = nativeEndian.Uint32(b[36:40])
  378. a.RXLengthErrors = nativeEndian.Uint32(b[40:44])
  379. a.RXOverErrors = nativeEndian.Uint32(b[44:48])
  380. a.RXCRCErrors = nativeEndian.Uint32(b[48:52])
  381. a.RXFrameErrors = nativeEndian.Uint32(b[52:56])
  382. a.RXFIFOErrors = nativeEndian.Uint32(b[56:60])
  383. a.RXMissedErrors = nativeEndian.Uint32(b[60:64])
  384. a.TXAbortedErrors = nativeEndian.Uint32(b[64:68])
  385. a.TXCarrierErrors = nativeEndian.Uint32(b[68:72])
  386. a.TXFIFOErrors = nativeEndian.Uint32(b[72:76])
  387. a.TXHeartbeatErrors = nativeEndian.Uint32(b[76:80])
  388. a.TXWindowErrors = nativeEndian.Uint32(b[80:84])
  389. a.RXCompressed = nativeEndian.Uint32(b[84:88])
  390. a.TXCompressed = nativeEndian.Uint32(b[88:92])
  391. if l == 96 { // kernel 4.6+
  392. a.RXNoHandler = nativeEndian.Uint32(b[92:96])
  393. }
  394. return nil
  395. }
  396. // LinkStats64 contains packet statistics
  397. type LinkStats64 struct {
  398. RXPackets uint64 // total packets received
  399. TXPackets uint64 // total packets transmitted
  400. RXBytes uint64 // total bytes received
  401. TXBytes uint64 // total bytes transmitted
  402. RXErrors uint64 // bad packets received
  403. TXErrors uint64 // packet transmit problems
  404. RXDropped uint64 // no space in linux buffers
  405. TXDropped uint64 // no space available in linux
  406. Multicast uint64 // multicast packets received
  407. Collisions uint64
  408. // detailed rx_errors:
  409. RXLengthErrors uint64
  410. RXOverErrors uint64 // receiver ring buff overflow
  411. RXCRCErrors uint64 // recved pkt with crc error
  412. RXFrameErrors uint64 // recv'd frame alignment error
  413. RXFIFOErrors uint64 // recv'r fifo overrun
  414. RXMissedErrors uint64 // receiver missed packet
  415. // detailed tx_errors
  416. TXAbortedErrors uint64
  417. TXCarrierErrors uint64
  418. TXFIFOErrors uint64
  419. TXHeartbeatErrors uint64
  420. TXWindowErrors uint64
  421. // for cslip etc
  422. RXCompressed uint64
  423. TXCompressed uint64
  424. RXNoHandler uint64 // dropped, no handler found
  425. RXOtherhostDropped uint64 // Number of packets dropped due to mismatch in destination MAC address.
  426. }
  427. // unmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
  428. func (a *LinkStats64) unmarshalBinary(b []byte) error {
  429. l := len(b)
  430. if l != 184 && l != 192 && l != 200 {
  431. return fmt.Errorf("incorrect size, want: 184 or 192 or 200")
  432. }
  433. a.RXPackets = nativeEndian.Uint64(b[0:8])
  434. a.TXPackets = nativeEndian.Uint64(b[8:16])
  435. a.RXBytes = nativeEndian.Uint64(b[16:24])
  436. a.TXBytes = nativeEndian.Uint64(b[24:32])
  437. a.RXErrors = nativeEndian.Uint64(b[32:40])
  438. a.TXErrors = nativeEndian.Uint64(b[40:48])
  439. a.RXDropped = nativeEndian.Uint64(b[48:56])
  440. a.TXDropped = nativeEndian.Uint64(b[56:64])
  441. a.Multicast = nativeEndian.Uint64(b[64:72])
  442. a.Collisions = nativeEndian.Uint64(b[72:80])
  443. a.RXLengthErrors = nativeEndian.Uint64(b[80:88])
  444. a.RXOverErrors = nativeEndian.Uint64(b[88:96])
  445. a.RXCRCErrors = nativeEndian.Uint64(b[96:104])
  446. a.RXFrameErrors = nativeEndian.Uint64(b[104:112])
  447. a.RXFIFOErrors = nativeEndian.Uint64(b[112:120])
  448. a.RXMissedErrors = nativeEndian.Uint64(b[120:128])
  449. a.TXAbortedErrors = nativeEndian.Uint64(b[128:136])
  450. a.TXCarrierErrors = nativeEndian.Uint64(b[136:144])
  451. a.TXFIFOErrors = nativeEndian.Uint64(b[144:152])
  452. a.TXHeartbeatErrors = nativeEndian.Uint64(b[152:160])
  453. a.TXWindowErrors = nativeEndian.Uint64(b[160:168])
  454. a.RXCompressed = nativeEndian.Uint64(b[168:176])
  455. a.TXCompressed = nativeEndian.Uint64(b[176:184])
  456. if l > 191 { // kernel 4.6+
  457. a.RXNoHandler = nativeEndian.Uint64(b[184:192])
  458. }
  459. if l > 199 { // kernel 5.19+
  460. a.RXOtherhostDropped = nativeEndian.Uint64(b[192:200])
  461. }
  462. return nil
  463. }
  464. // LinkInfo contains data for specific network types
  465. type LinkInfo struct {
  466. Kind string // Driver name
  467. Data []byte // Driver specific configuration stored as nested Netlink messages
  468. SlaveKind string // Slave driver name
  469. SlaveData []byte // Slave driver specific configuration
  470. }
  471. func (i *LinkInfo) decode(ad *netlink.AttributeDecoder) error {
  472. for ad.Next() {
  473. switch ad.Type() {
  474. case unix.IFLA_INFO_KIND:
  475. i.Kind = ad.String()
  476. case unix.IFLA_INFO_SLAVE_KIND:
  477. i.SlaveKind = ad.String()
  478. case unix.IFLA_INFO_DATA:
  479. i.Data = ad.Bytes()
  480. case unix.IFLA_INFO_SLAVE_DATA:
  481. i.SlaveData = ad.Bytes()
  482. }
  483. }
  484. return nil
  485. }
  486. func (i *LinkInfo) encode(ae *netlink.AttributeEncoder) error {
  487. ae.String(unix.IFLA_INFO_KIND, i.Kind)
  488. ae.Bytes(unix.IFLA_INFO_DATA, i.Data)
  489. if len(i.SlaveData) > 0 {
  490. ae.String(unix.IFLA_INFO_SLAVE_KIND, i.SlaveKind)
  491. ae.Bytes(unix.IFLA_INFO_SLAVE_DATA, i.SlaveData)
  492. }
  493. return nil
  494. }
  495. // LinkXDP holds Express Data Path specific information
  496. type LinkXDP struct {
  497. FD int32
  498. ExpectedFD int32
  499. Attached uint8
  500. Flags uint32
  501. ProgID uint32
  502. }
  503. func (xdp *LinkXDP) decode(ad *netlink.AttributeDecoder) error {
  504. for ad.Next() {
  505. switch ad.Type() {
  506. case unix.IFLA_XDP_FD:
  507. xdp.FD = ad.Int32()
  508. case unix.IFLA_XDP_EXPECTED_FD:
  509. xdp.ExpectedFD = ad.Int32()
  510. case unix.IFLA_XDP_ATTACHED:
  511. xdp.Attached = ad.Uint8()
  512. case unix.IFLA_XDP_FLAGS:
  513. xdp.Flags = ad.Uint32()
  514. case unix.IFLA_XDP_PROG_ID:
  515. xdp.ProgID = ad.Uint32()
  516. }
  517. }
  518. return nil
  519. }
  520. func (xdp *LinkXDP) encode(ae *netlink.AttributeEncoder) error {
  521. ae.Int32(unix.IFLA_XDP_FD, xdp.FD)
  522. ae.Int32(unix.IFLA_XDP_EXPECTED_FD, xdp.ExpectedFD)
  523. ae.Uint32(unix.IFLA_XDP_FLAGS, xdp.Flags)
  524. // XDP_ATtACHED and XDP_PROG_ID are things that only can return from the kernel,
  525. // not be send, so we don't encode them.
  526. // source: https://elixir.bootlin.com/linux/v5.10.15/source/net/core/rtnetlink.c#L2894
  527. return nil
  528. }