nl_linux.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. // Package nl has low level primitives for making Netlink calls.
  2. package nl
  3. import (
  4. "bytes"
  5. "encoding/binary"
  6. "fmt"
  7. "net"
  8. "runtime"
  9. "sync"
  10. "sync/atomic"
  11. "syscall"
  12. "unsafe"
  13. "github.com/vishvananda/netns"
  14. )
  15. const (
  16. // Family type definitions
  17. FAMILY_ALL = syscall.AF_UNSPEC
  18. FAMILY_V4 = syscall.AF_INET
  19. FAMILY_V6 = syscall.AF_INET6
  20. FAMILY_MPLS = AF_MPLS
  21. )
  22. // SupportedNlFamilies contains the list of netlink families this netlink package supports
  23. var SupportedNlFamilies = []int{syscall.NETLINK_ROUTE, syscall.NETLINK_XFRM, syscall.NETLINK_NETFILTER}
  24. var nextSeqNr uint32
  25. // GetIPFamily returns the family type of a net.IP.
  26. func GetIPFamily(ip net.IP) int {
  27. if len(ip) <= net.IPv4len {
  28. return FAMILY_V4
  29. }
  30. if ip.To4() != nil {
  31. return FAMILY_V4
  32. }
  33. return FAMILY_V6
  34. }
  35. var nativeEndian binary.ByteOrder
  36. // Get native endianness for the system
  37. func NativeEndian() binary.ByteOrder {
  38. if nativeEndian == nil {
  39. var x uint32 = 0x01020304
  40. if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
  41. nativeEndian = binary.BigEndian
  42. } else {
  43. nativeEndian = binary.LittleEndian
  44. }
  45. }
  46. return nativeEndian
  47. }
  48. // Byte swap a 16 bit value if we aren't big endian
  49. func Swap16(i uint16) uint16 {
  50. if NativeEndian() == binary.BigEndian {
  51. return i
  52. }
  53. return (i&0xff00)>>8 | (i&0xff)<<8
  54. }
  55. // Byte swap a 32 bit value if aren't big endian
  56. func Swap32(i uint32) uint32 {
  57. if NativeEndian() == binary.BigEndian {
  58. return i
  59. }
  60. return (i&0xff000000)>>24 | (i&0xff0000)>>8 | (i&0xff00)<<8 | (i&0xff)<<24
  61. }
  62. type NetlinkRequestData interface {
  63. Len() int
  64. Serialize() []byte
  65. }
  66. // IfInfomsg is related to links, but it is used for list requests as well
  67. type IfInfomsg struct {
  68. syscall.IfInfomsg
  69. }
  70. // Create an IfInfomsg with family specified
  71. func NewIfInfomsg(family int) *IfInfomsg {
  72. return &IfInfomsg{
  73. IfInfomsg: syscall.IfInfomsg{
  74. Family: uint8(family),
  75. },
  76. }
  77. }
  78. func DeserializeIfInfomsg(b []byte) *IfInfomsg {
  79. return (*IfInfomsg)(unsafe.Pointer(&b[0:syscall.SizeofIfInfomsg][0]))
  80. }
  81. func (msg *IfInfomsg) Serialize() []byte {
  82. return (*(*[syscall.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:]
  83. }
  84. func (msg *IfInfomsg) Len() int {
  85. return syscall.SizeofIfInfomsg
  86. }
  87. func (msg *IfInfomsg) EncapType() string {
  88. switch msg.Type {
  89. case 0:
  90. return "generic"
  91. case syscall.ARPHRD_ETHER:
  92. return "ether"
  93. case syscall.ARPHRD_EETHER:
  94. return "eether"
  95. case syscall.ARPHRD_AX25:
  96. return "ax25"
  97. case syscall.ARPHRD_PRONET:
  98. return "pronet"
  99. case syscall.ARPHRD_CHAOS:
  100. return "chaos"
  101. case syscall.ARPHRD_IEEE802:
  102. return "ieee802"
  103. case syscall.ARPHRD_ARCNET:
  104. return "arcnet"
  105. case syscall.ARPHRD_APPLETLK:
  106. return "atalk"
  107. case syscall.ARPHRD_DLCI:
  108. return "dlci"
  109. case syscall.ARPHRD_ATM:
  110. return "atm"
  111. case syscall.ARPHRD_METRICOM:
  112. return "metricom"
  113. case syscall.ARPHRD_IEEE1394:
  114. return "ieee1394"
  115. case syscall.ARPHRD_INFINIBAND:
  116. return "infiniband"
  117. case syscall.ARPHRD_SLIP:
  118. return "slip"
  119. case syscall.ARPHRD_CSLIP:
  120. return "cslip"
  121. case syscall.ARPHRD_SLIP6:
  122. return "slip6"
  123. case syscall.ARPHRD_CSLIP6:
  124. return "cslip6"
  125. case syscall.ARPHRD_RSRVD:
  126. return "rsrvd"
  127. case syscall.ARPHRD_ADAPT:
  128. return "adapt"
  129. case syscall.ARPHRD_ROSE:
  130. return "rose"
  131. case syscall.ARPHRD_X25:
  132. return "x25"
  133. case syscall.ARPHRD_HWX25:
  134. return "hwx25"
  135. case syscall.ARPHRD_PPP:
  136. return "ppp"
  137. case syscall.ARPHRD_HDLC:
  138. return "hdlc"
  139. case syscall.ARPHRD_LAPB:
  140. return "lapb"
  141. case syscall.ARPHRD_DDCMP:
  142. return "ddcmp"
  143. case syscall.ARPHRD_RAWHDLC:
  144. return "rawhdlc"
  145. case syscall.ARPHRD_TUNNEL:
  146. return "ipip"
  147. case syscall.ARPHRD_TUNNEL6:
  148. return "tunnel6"
  149. case syscall.ARPHRD_FRAD:
  150. return "frad"
  151. case syscall.ARPHRD_SKIP:
  152. return "skip"
  153. case syscall.ARPHRD_LOOPBACK:
  154. return "loopback"
  155. case syscall.ARPHRD_LOCALTLK:
  156. return "ltalk"
  157. case syscall.ARPHRD_FDDI:
  158. return "fddi"
  159. case syscall.ARPHRD_BIF:
  160. return "bif"
  161. case syscall.ARPHRD_SIT:
  162. return "sit"
  163. case syscall.ARPHRD_IPDDP:
  164. return "ip/ddp"
  165. case syscall.ARPHRD_IPGRE:
  166. return "gre"
  167. case syscall.ARPHRD_PIMREG:
  168. return "pimreg"
  169. case syscall.ARPHRD_HIPPI:
  170. return "hippi"
  171. case syscall.ARPHRD_ASH:
  172. return "ash"
  173. case syscall.ARPHRD_ECONET:
  174. return "econet"
  175. case syscall.ARPHRD_IRDA:
  176. return "irda"
  177. case syscall.ARPHRD_FCPP:
  178. return "fcpp"
  179. case syscall.ARPHRD_FCAL:
  180. return "fcal"
  181. case syscall.ARPHRD_FCPL:
  182. return "fcpl"
  183. case syscall.ARPHRD_FCFABRIC:
  184. return "fcfb0"
  185. case syscall.ARPHRD_FCFABRIC + 1:
  186. return "fcfb1"
  187. case syscall.ARPHRD_FCFABRIC + 2:
  188. return "fcfb2"
  189. case syscall.ARPHRD_FCFABRIC + 3:
  190. return "fcfb3"
  191. case syscall.ARPHRD_FCFABRIC + 4:
  192. return "fcfb4"
  193. case syscall.ARPHRD_FCFABRIC + 5:
  194. return "fcfb5"
  195. case syscall.ARPHRD_FCFABRIC + 6:
  196. return "fcfb6"
  197. case syscall.ARPHRD_FCFABRIC + 7:
  198. return "fcfb7"
  199. case syscall.ARPHRD_FCFABRIC + 8:
  200. return "fcfb8"
  201. case syscall.ARPHRD_FCFABRIC + 9:
  202. return "fcfb9"
  203. case syscall.ARPHRD_FCFABRIC + 10:
  204. return "fcfb10"
  205. case syscall.ARPHRD_FCFABRIC + 11:
  206. return "fcfb11"
  207. case syscall.ARPHRD_FCFABRIC + 12:
  208. return "fcfb12"
  209. case syscall.ARPHRD_IEEE802_TR:
  210. return "tr"
  211. case syscall.ARPHRD_IEEE80211:
  212. return "ieee802.11"
  213. case syscall.ARPHRD_IEEE80211_PRISM:
  214. return "ieee802.11/prism"
  215. case syscall.ARPHRD_IEEE80211_RADIOTAP:
  216. return "ieee802.11/radiotap"
  217. case syscall.ARPHRD_IEEE802154:
  218. return "ieee802.15.4"
  219. case 65534:
  220. return "none"
  221. case 65535:
  222. return "void"
  223. }
  224. return fmt.Sprintf("unknown%d", msg.Type)
  225. }
  226. func rtaAlignOf(attrlen int) int {
  227. return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
  228. }
  229. func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
  230. msg := NewIfInfomsg(family)
  231. parent.children = append(parent.children, msg)
  232. return msg
  233. }
  234. // Extend RtAttr to handle data and children
  235. type RtAttr struct {
  236. syscall.RtAttr
  237. Data []byte
  238. children []NetlinkRequestData
  239. }
  240. // Create a new Extended RtAttr object
  241. func NewRtAttr(attrType int, data []byte) *RtAttr {
  242. return &RtAttr{
  243. RtAttr: syscall.RtAttr{
  244. Type: uint16(attrType),
  245. },
  246. children: []NetlinkRequestData{},
  247. Data: data,
  248. }
  249. }
  250. // Create a new RtAttr obj anc add it as a child of an existing object
  251. func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
  252. attr := NewRtAttr(attrType, data)
  253. parent.children = append(parent.children, attr)
  254. return attr
  255. }
  256. func (a *RtAttr) Len() int {
  257. if len(a.children) == 0 {
  258. return (syscall.SizeofRtAttr + len(a.Data))
  259. }
  260. l := 0
  261. for _, child := range a.children {
  262. l += rtaAlignOf(child.Len())
  263. }
  264. l += syscall.SizeofRtAttr
  265. return rtaAlignOf(l + len(a.Data))
  266. }
  267. // Serialize the RtAttr into a byte array
  268. // This can't just unsafe.cast because it must iterate through children.
  269. func (a *RtAttr) Serialize() []byte {
  270. native := NativeEndian()
  271. length := a.Len()
  272. buf := make([]byte, rtaAlignOf(length))
  273. next := 4
  274. if a.Data != nil {
  275. copy(buf[next:], a.Data)
  276. next += rtaAlignOf(len(a.Data))
  277. }
  278. if len(a.children) > 0 {
  279. for _, child := range a.children {
  280. childBuf := child.Serialize()
  281. copy(buf[next:], childBuf)
  282. next += rtaAlignOf(len(childBuf))
  283. }
  284. }
  285. if l := uint16(length); l != 0 {
  286. native.PutUint16(buf[0:2], l)
  287. }
  288. native.PutUint16(buf[2:4], a.Type)
  289. return buf
  290. }
  291. type NetlinkRequest struct {
  292. syscall.NlMsghdr
  293. Data []NetlinkRequestData
  294. RawData []byte
  295. Sockets map[int]*SocketHandle
  296. }
  297. // Serialize the Netlink Request into a byte array
  298. func (req *NetlinkRequest) Serialize() []byte {
  299. length := syscall.SizeofNlMsghdr
  300. dataBytes := make([][]byte, len(req.Data))
  301. for i, data := range req.Data {
  302. dataBytes[i] = data.Serialize()
  303. length = length + len(dataBytes[i])
  304. }
  305. length += len(req.RawData)
  306. req.Len = uint32(length)
  307. b := make([]byte, length)
  308. hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
  309. next := syscall.SizeofNlMsghdr
  310. copy(b[0:next], hdr)
  311. for _, data := range dataBytes {
  312. for _, dataByte := range data {
  313. b[next] = dataByte
  314. next = next + 1
  315. }
  316. }
  317. // Add the raw data if any
  318. if len(req.RawData) > 0 {
  319. copy(b[next:length], req.RawData)
  320. }
  321. return b
  322. }
  323. func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
  324. if data != nil {
  325. req.Data = append(req.Data, data)
  326. }
  327. }
  328. // AddRawData adds raw bytes to the end of the NetlinkRequest object during serialization
  329. func (req *NetlinkRequest) AddRawData(data []byte) {
  330. if data != nil {
  331. req.RawData = append(req.RawData, data...)
  332. }
  333. }
  334. // Execute the request against a the given sockType.
  335. // Returns a list of netlink messages in serialized format, optionally filtered
  336. // by resType.
  337. func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, error) {
  338. var (
  339. s *NetlinkSocket
  340. err error
  341. )
  342. if req.Sockets != nil {
  343. if sh, ok := req.Sockets[sockType]; ok {
  344. s = sh.Socket
  345. req.Seq = atomic.AddUint32(&sh.Seq, 1)
  346. }
  347. }
  348. sharedSocket := s != nil
  349. if s == nil {
  350. s, err = getNetlinkSocket(sockType)
  351. if err != nil {
  352. return nil, err
  353. }
  354. defer s.Close()
  355. } else {
  356. s.Lock()
  357. defer s.Unlock()
  358. }
  359. if err := s.Send(req); err != nil {
  360. return nil, err
  361. }
  362. pid, err := s.GetPid()
  363. if err != nil {
  364. return nil, err
  365. }
  366. var res [][]byte
  367. done:
  368. for {
  369. msgs, err := s.Receive()
  370. if err != nil {
  371. return nil, err
  372. }
  373. for _, m := range msgs {
  374. if m.Header.Seq != req.Seq {
  375. if sharedSocket {
  376. continue
  377. }
  378. return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq)
  379. }
  380. if m.Header.Pid != pid {
  381. return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
  382. }
  383. if m.Header.Type == syscall.NLMSG_DONE {
  384. break done
  385. }
  386. if m.Header.Type == syscall.NLMSG_ERROR {
  387. native := NativeEndian()
  388. error := int32(native.Uint32(m.Data[0:4]))
  389. if error == 0 {
  390. break done
  391. }
  392. return nil, syscall.Errno(-error)
  393. }
  394. if resType != 0 && m.Header.Type != resType {
  395. continue
  396. }
  397. res = append(res, m.Data)
  398. if m.Header.Flags&syscall.NLM_F_MULTI == 0 {
  399. break done
  400. }
  401. }
  402. }
  403. return res, nil
  404. }
  405. // Create a new netlink request from proto and flags
  406. // Note the Len value will be inaccurate once data is added until
  407. // the message is serialized
  408. func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
  409. return &NetlinkRequest{
  410. NlMsghdr: syscall.NlMsghdr{
  411. Len: uint32(syscall.SizeofNlMsghdr),
  412. Type: uint16(proto),
  413. Flags: syscall.NLM_F_REQUEST | uint16(flags),
  414. Seq: atomic.AddUint32(&nextSeqNr, 1),
  415. },
  416. }
  417. }
  418. type NetlinkSocket struct {
  419. fd int32
  420. lsa syscall.SockaddrNetlink
  421. sync.Mutex
  422. }
  423. func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
  424. fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW|syscall.SOCK_CLOEXEC, protocol)
  425. if err != nil {
  426. return nil, err
  427. }
  428. s := &NetlinkSocket{
  429. fd: int32(fd),
  430. }
  431. s.lsa.Family = syscall.AF_NETLINK
  432. if err := syscall.Bind(fd, &s.lsa); err != nil {
  433. syscall.Close(fd)
  434. return nil, err
  435. }
  436. return s, nil
  437. }
  438. // GetNetlinkSocketAt opens a netlink socket in the network namespace newNs
  439. // and positions the thread back into the network namespace specified by curNs,
  440. // when done. If curNs is close, the function derives the current namespace and
  441. // moves back into it when done. If newNs is close, the socket will be opened
  442. // in the current network namespace.
  443. func GetNetlinkSocketAt(newNs, curNs netns.NsHandle, protocol int) (*NetlinkSocket, error) {
  444. c, err := executeInNetns(newNs, curNs)
  445. if err != nil {
  446. return nil, err
  447. }
  448. defer c()
  449. return getNetlinkSocket(protocol)
  450. }
  451. // executeInNetns sets execution of the code following this call to the
  452. // network namespace newNs, then moves the thread back to curNs if open,
  453. // otherwise to the current netns at the time the function was invoked
  454. // In case of success, the caller is expected to execute the returned function
  455. // at the end of the code that needs to be executed in the network namespace.
  456. // Example:
  457. // func jobAt(...) error {
  458. // d, err := executeInNetns(...)
  459. // if err != nil { return err}
  460. // defer d()
  461. // < code which needs to be executed in specific netns>
  462. // }
  463. // TODO: his function probably belongs to netns pkg.
  464. func executeInNetns(newNs, curNs netns.NsHandle) (func(), error) {
  465. var (
  466. err error
  467. moveBack func(netns.NsHandle) error
  468. closeNs func() error
  469. unlockThd func()
  470. )
  471. restore := func() {
  472. // order matters
  473. if moveBack != nil {
  474. moveBack(curNs)
  475. }
  476. if closeNs != nil {
  477. closeNs()
  478. }
  479. if unlockThd != nil {
  480. unlockThd()
  481. }
  482. }
  483. if newNs.IsOpen() {
  484. runtime.LockOSThread()
  485. unlockThd = runtime.UnlockOSThread
  486. if !curNs.IsOpen() {
  487. if curNs, err = netns.Get(); err != nil {
  488. restore()
  489. return nil, fmt.Errorf("could not get current namespace while creating netlink socket: %v", err)
  490. }
  491. closeNs = curNs.Close
  492. }
  493. if err := netns.Set(newNs); err != nil {
  494. restore()
  495. return nil, fmt.Errorf("failed to set into network namespace %d while creating netlink socket: %v", newNs, err)
  496. }
  497. moveBack = netns.Set
  498. }
  499. return restore, nil
  500. }
  501. // Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE)
  502. // and subscribe it to multicast groups passed in variable argument list.
  503. // Returns the netlink socket on which Receive() method can be called
  504. // to retrieve the messages from the kernel.
  505. func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
  506. fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
  507. if err != nil {
  508. return nil, err
  509. }
  510. s := &NetlinkSocket{
  511. fd: int32(fd),
  512. }
  513. s.lsa.Family = syscall.AF_NETLINK
  514. for _, g := range groups {
  515. s.lsa.Groups |= (1 << (g - 1))
  516. }
  517. if err := syscall.Bind(fd, &s.lsa); err != nil {
  518. syscall.Close(fd)
  519. return nil, err
  520. }
  521. return s, nil
  522. }
  523. // SubscribeAt works like Subscribe plus let's the caller choose the network
  524. // namespace in which the socket would be opened (newNs). Then control goes back
  525. // to curNs if open, otherwise to the netns at the time this function was called.
  526. func SubscribeAt(newNs, curNs netns.NsHandle, protocol int, groups ...uint) (*NetlinkSocket, error) {
  527. c, err := executeInNetns(newNs, curNs)
  528. if err != nil {
  529. return nil, err
  530. }
  531. defer c()
  532. return Subscribe(protocol, groups...)
  533. }
  534. func (s *NetlinkSocket) Close() {
  535. fd := int(atomic.SwapInt32(&s.fd, -1))
  536. syscall.Close(fd)
  537. }
  538. func (s *NetlinkSocket) GetFd() int {
  539. return int(atomic.LoadInt32(&s.fd))
  540. }
  541. func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
  542. fd := int(atomic.LoadInt32(&s.fd))
  543. if fd < 0 {
  544. return fmt.Errorf("Send called on a closed socket")
  545. }
  546. if err := syscall.Sendto(fd, request.Serialize(), 0, &s.lsa); err != nil {
  547. return err
  548. }
  549. return nil
  550. }
  551. func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
  552. fd := int(atomic.LoadInt32(&s.fd))
  553. if fd < 0 {
  554. return nil, fmt.Errorf("Receive called on a closed socket")
  555. }
  556. rb := make([]byte, syscall.Getpagesize())
  557. nr, _, err := syscall.Recvfrom(fd, rb, 0)
  558. if err != nil {
  559. return nil, err
  560. }
  561. if nr < syscall.NLMSG_HDRLEN {
  562. return nil, fmt.Errorf("Got short response from netlink")
  563. }
  564. rb = rb[:nr]
  565. return syscall.ParseNetlinkMessage(rb)
  566. }
  567. func (s *NetlinkSocket) GetPid() (uint32, error) {
  568. fd := int(atomic.LoadInt32(&s.fd))
  569. lsa, err := syscall.Getsockname(fd)
  570. if err != nil {
  571. return 0, err
  572. }
  573. switch v := lsa.(type) {
  574. case *syscall.SockaddrNetlink:
  575. return v.Pid, nil
  576. }
  577. return 0, fmt.Errorf("Wrong socket type")
  578. }
  579. func ZeroTerminated(s string) []byte {
  580. bytes := make([]byte, len(s)+1)
  581. for i := 0; i < len(s); i++ {
  582. bytes[i] = s[i]
  583. }
  584. bytes[len(s)] = 0
  585. return bytes
  586. }
  587. func NonZeroTerminated(s string) []byte {
  588. bytes := make([]byte, len(s))
  589. for i := 0; i < len(s); i++ {
  590. bytes[i] = s[i]
  591. }
  592. return bytes
  593. }
  594. func BytesToString(b []byte) string {
  595. n := bytes.Index(b, []byte{0})
  596. return string(b[:n])
  597. }
  598. func Uint8Attr(v uint8) []byte {
  599. return []byte{byte(v)}
  600. }
  601. func Uint16Attr(v uint16) []byte {
  602. native := NativeEndian()
  603. bytes := make([]byte, 2)
  604. native.PutUint16(bytes, v)
  605. return bytes
  606. }
  607. func Uint32Attr(v uint32) []byte {
  608. native := NativeEndian()
  609. bytes := make([]byte, 4)
  610. native.PutUint32(bytes, v)
  611. return bytes
  612. }
  613. func Uint64Attr(v uint64) []byte {
  614. native := NativeEndian()
  615. bytes := make([]byte, 8)
  616. native.PutUint64(bytes, v)
  617. return bytes
  618. }
  619. func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
  620. var attrs []syscall.NetlinkRouteAttr
  621. for len(b) >= syscall.SizeofRtAttr {
  622. a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
  623. if err != nil {
  624. return nil, err
  625. }
  626. ra := syscall.NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-syscall.SizeofRtAttr]}
  627. attrs = append(attrs, ra)
  628. b = b[alen:]
  629. }
  630. return attrs, nil
  631. }
  632. func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) {
  633. a := (*syscall.RtAttr)(unsafe.Pointer(&b[0]))
  634. if int(a.Len) < syscall.SizeofRtAttr || int(a.Len) > len(b) {
  635. return nil, nil, 0, syscall.EINVAL
  636. }
  637. return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
  638. }
  639. // SocketHandle contains the netlink socket and the associated
  640. // sequence counter for a specific netlink family
  641. type SocketHandle struct {
  642. Seq uint32
  643. Socket *NetlinkSocket
  644. }
  645. // Close closes the netlink socket
  646. func (sh *SocketHandle) Close() {
  647. if sh.Socket != nil {
  648. sh.Socket.Close()
  649. }
  650. }