nl_linux.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  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}
  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. Sockets map[int]*SocketHandle
  295. }
  296. // Serialize the Netlink Request into a byte array
  297. func (req *NetlinkRequest) Serialize() []byte {
  298. length := syscall.SizeofNlMsghdr
  299. dataBytes := make([][]byte, len(req.Data))
  300. for i, data := range req.Data {
  301. dataBytes[i] = data.Serialize()
  302. length = length + len(dataBytes[i])
  303. }
  304. req.Len = uint32(length)
  305. b := make([]byte, length)
  306. hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
  307. next := syscall.SizeofNlMsghdr
  308. copy(b[0:next], hdr)
  309. for _, data := range dataBytes {
  310. for _, dataByte := range data {
  311. b[next] = dataByte
  312. next = next + 1
  313. }
  314. }
  315. return b
  316. }
  317. func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
  318. if data != nil {
  319. req.Data = append(req.Data, data)
  320. }
  321. }
  322. // Execute the request against a the given sockType.
  323. // Returns a list of netlink messages in serialized format, optionally filtered
  324. // by resType.
  325. func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, error) {
  326. var (
  327. s *NetlinkSocket
  328. err error
  329. )
  330. if req.Sockets != nil {
  331. if sh, ok := req.Sockets[sockType]; ok {
  332. s = sh.Socket
  333. req.Seq = atomic.AddUint32(&sh.Seq, 1)
  334. }
  335. }
  336. sharedSocket := s != nil
  337. if s == nil {
  338. s, err = getNetlinkSocket(sockType)
  339. if err != nil {
  340. return nil, err
  341. }
  342. defer s.Close()
  343. } else {
  344. s.Lock()
  345. defer s.Unlock()
  346. }
  347. if err := s.Send(req); err != nil {
  348. return nil, err
  349. }
  350. pid, err := s.GetPid()
  351. if err != nil {
  352. return nil, err
  353. }
  354. var res [][]byte
  355. done:
  356. for {
  357. msgs, err := s.Receive()
  358. if err != nil {
  359. return nil, err
  360. }
  361. for _, m := range msgs {
  362. if m.Header.Seq != req.Seq {
  363. if sharedSocket {
  364. continue
  365. }
  366. return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq)
  367. }
  368. if m.Header.Pid != pid {
  369. return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
  370. }
  371. if m.Header.Type == syscall.NLMSG_DONE {
  372. break done
  373. }
  374. if m.Header.Type == syscall.NLMSG_ERROR {
  375. native := NativeEndian()
  376. error := int32(native.Uint32(m.Data[0:4]))
  377. if error == 0 {
  378. break done
  379. }
  380. return nil, syscall.Errno(-error)
  381. }
  382. if resType != 0 && m.Header.Type != resType {
  383. continue
  384. }
  385. res = append(res, m.Data)
  386. if m.Header.Flags&syscall.NLM_F_MULTI == 0 {
  387. break done
  388. }
  389. }
  390. }
  391. return res, nil
  392. }
  393. // Create a new netlink request from proto and flags
  394. // Note the Len value will be inaccurate once data is added until
  395. // the message is serialized
  396. func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
  397. return &NetlinkRequest{
  398. NlMsghdr: syscall.NlMsghdr{
  399. Len: uint32(syscall.SizeofNlMsghdr),
  400. Type: uint16(proto),
  401. Flags: syscall.NLM_F_REQUEST | uint16(flags),
  402. Seq: atomic.AddUint32(&nextSeqNr, 1),
  403. },
  404. }
  405. }
  406. type NetlinkSocket struct {
  407. fd int
  408. lsa syscall.SockaddrNetlink
  409. sync.Mutex
  410. }
  411. func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
  412. fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
  413. if err != nil {
  414. return nil, err
  415. }
  416. s := &NetlinkSocket{
  417. fd: fd,
  418. }
  419. s.lsa.Family = syscall.AF_NETLINK
  420. if err := syscall.Bind(fd, &s.lsa); err != nil {
  421. syscall.Close(fd)
  422. return nil, err
  423. }
  424. return s, nil
  425. }
  426. // GetNetlinkSocketAt opens a netlink socket in the network namespace newNs
  427. // and positions the thread back into the network namespace specified by curNs,
  428. // when done. If curNs is close, the function derives the current namespace and
  429. // moves back into it when done. If newNs is close, the socket will be opened
  430. // in the current network namespace.
  431. func GetNetlinkSocketAt(newNs, curNs netns.NsHandle, protocol int) (*NetlinkSocket, error) {
  432. c, err := executeInNetns(newNs, curNs)
  433. if err != nil {
  434. return nil, err
  435. }
  436. defer c()
  437. return getNetlinkSocket(protocol)
  438. }
  439. // executeInNetns sets execution of the code following this call to the
  440. // network namespace newNs, then moves the thread back to curNs if open,
  441. // otherwise to the current netns at the time the function was invoked
  442. // In case of success, the caller is expected to execute the returned function
  443. // at the end of the code that needs to be executed in the network namespace.
  444. // Example:
  445. // func jobAt(...) error {
  446. // d, err := executeInNetns(...)
  447. // if err != nil { return err}
  448. // defer d()
  449. // < code which needs to be executed in specific netns>
  450. // }
  451. // TODO: his function probably belongs to netns pkg.
  452. func executeInNetns(newNs, curNs netns.NsHandle) (func(), error) {
  453. var (
  454. err error
  455. moveBack func(netns.NsHandle) error
  456. closeNs func() error
  457. unlockThd func()
  458. )
  459. restore := func() {
  460. // order matters
  461. if moveBack != nil {
  462. moveBack(curNs)
  463. }
  464. if closeNs != nil {
  465. closeNs()
  466. }
  467. if unlockThd != nil {
  468. unlockThd()
  469. }
  470. }
  471. if newNs.IsOpen() {
  472. runtime.LockOSThread()
  473. unlockThd = runtime.UnlockOSThread
  474. if !curNs.IsOpen() {
  475. if curNs, err = netns.Get(); err != nil {
  476. restore()
  477. return nil, fmt.Errorf("could not get current namespace while creating netlink socket: %v", err)
  478. }
  479. closeNs = curNs.Close
  480. }
  481. if err := netns.Set(newNs); err != nil {
  482. restore()
  483. return nil, fmt.Errorf("failed to set into network namespace %d while creating netlink socket: %v", newNs, err)
  484. }
  485. moveBack = netns.Set
  486. }
  487. return restore, nil
  488. }
  489. // Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE)
  490. // and subscribe it to multicast groups passed in variable argument list.
  491. // Returns the netlink socket on which Receive() method can be called
  492. // to retrieve the messages from the kernel.
  493. func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
  494. fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
  495. if err != nil {
  496. return nil, err
  497. }
  498. s := &NetlinkSocket{
  499. fd: fd,
  500. }
  501. s.lsa.Family = syscall.AF_NETLINK
  502. for _, g := range groups {
  503. s.lsa.Groups |= (1 << (g - 1))
  504. }
  505. if err := syscall.Bind(fd, &s.lsa); err != nil {
  506. syscall.Close(fd)
  507. return nil, err
  508. }
  509. return s, nil
  510. }
  511. // SubscribeAt works like Subscribe plus let's the caller choose the network
  512. // namespace in which the socket would be opened (newNs). Then control goes back
  513. // to curNs if open, otherwise to the netns at the time this function was called.
  514. func SubscribeAt(newNs, curNs netns.NsHandle, protocol int, groups ...uint) (*NetlinkSocket, error) {
  515. c, err := executeInNetns(newNs, curNs)
  516. if err != nil {
  517. return nil, err
  518. }
  519. defer c()
  520. return Subscribe(protocol, groups...)
  521. }
  522. func (s *NetlinkSocket) Close() {
  523. syscall.Close(s.fd)
  524. s.fd = -1
  525. }
  526. func (s *NetlinkSocket) GetFd() int {
  527. return s.fd
  528. }
  529. func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
  530. if s.fd < 0 {
  531. return fmt.Errorf("Send called on a closed socket")
  532. }
  533. if err := syscall.Sendto(s.fd, request.Serialize(), 0, &s.lsa); err != nil {
  534. return err
  535. }
  536. return nil
  537. }
  538. func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
  539. if s.fd < 0 {
  540. return nil, fmt.Errorf("Receive called on a closed socket")
  541. }
  542. rb := make([]byte, syscall.Getpagesize())
  543. nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
  544. if err != nil {
  545. return nil, err
  546. }
  547. if nr < syscall.NLMSG_HDRLEN {
  548. return nil, fmt.Errorf("Got short response from netlink")
  549. }
  550. rb = rb[:nr]
  551. return syscall.ParseNetlinkMessage(rb)
  552. }
  553. func (s *NetlinkSocket) GetPid() (uint32, error) {
  554. lsa, err := syscall.Getsockname(s.fd)
  555. if err != nil {
  556. return 0, err
  557. }
  558. switch v := lsa.(type) {
  559. case *syscall.SockaddrNetlink:
  560. return v.Pid, nil
  561. }
  562. return 0, fmt.Errorf("Wrong socket type")
  563. }
  564. func ZeroTerminated(s string) []byte {
  565. bytes := make([]byte, len(s)+1)
  566. for i := 0; i < len(s); i++ {
  567. bytes[i] = s[i]
  568. }
  569. bytes[len(s)] = 0
  570. return bytes
  571. }
  572. func NonZeroTerminated(s string) []byte {
  573. bytes := make([]byte, len(s))
  574. for i := 0; i < len(s); i++ {
  575. bytes[i] = s[i]
  576. }
  577. return bytes
  578. }
  579. func BytesToString(b []byte) string {
  580. n := bytes.Index(b, []byte{0})
  581. return string(b[:n])
  582. }
  583. func Uint8Attr(v uint8) []byte {
  584. return []byte{byte(v)}
  585. }
  586. func Uint16Attr(v uint16) []byte {
  587. native := NativeEndian()
  588. bytes := make([]byte, 2)
  589. native.PutUint16(bytes, v)
  590. return bytes
  591. }
  592. func Uint32Attr(v uint32) []byte {
  593. native := NativeEndian()
  594. bytes := make([]byte, 4)
  595. native.PutUint32(bytes, v)
  596. return bytes
  597. }
  598. func Uint64Attr(v uint64) []byte {
  599. native := NativeEndian()
  600. bytes := make([]byte, 8)
  601. native.PutUint64(bytes, v)
  602. return bytes
  603. }
  604. func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
  605. var attrs []syscall.NetlinkRouteAttr
  606. for len(b) >= syscall.SizeofRtAttr {
  607. a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
  608. if err != nil {
  609. return nil, err
  610. }
  611. ra := syscall.NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-syscall.SizeofRtAttr]}
  612. attrs = append(attrs, ra)
  613. b = b[alen:]
  614. }
  615. return attrs, nil
  616. }
  617. func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) {
  618. a := (*syscall.RtAttr)(unsafe.Pointer(&b[0]))
  619. if int(a.Len) < syscall.SizeofRtAttr || int(a.Len) > len(b) {
  620. return nil, nil, 0, syscall.EINVAL
  621. }
  622. return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
  623. }
  624. // SocketHandle contains the netlink socket and the associated
  625. // sequence counter for a specific netlink family
  626. type SocketHandle struct {
  627. Seq uint32
  628. Socket *NetlinkSocket
  629. }
  630. // Close closes the netlink socket
  631. func (sh *SocketHandle) Close() {
  632. if sh.Socket != nil {
  633. sh.Socket.Close()
  634. }
  635. }