neigh.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. // errInvalidNeighMessage is returned when a LinkMessage is malformed.
  11. errInvalidNeighMessage = errors.New("rtnetlink NeighMessage is invalid or too short")
  12. // errInvalidNeighMessageAttr is returned when neigh attributes are malformed.
  13. errInvalidNeighMessageAttr = errors.New("rtnetlink NeighMessage has a wrong attribute data length")
  14. )
  15. var _ Message = &NeighMessage{}
  16. // A NeighMessage is a route netlink neighbor message.
  17. type NeighMessage struct {
  18. // Always set to AF_UNSPEC (0)
  19. Family uint16
  20. // Unique interface index
  21. Index uint32
  22. // Neighbor State is a bitmask of neighbor states (see rtnetlink(7))
  23. State uint16
  24. // Neighbor flags
  25. Flags uint8
  26. // Neighbor type
  27. Type uint8
  28. // Attributes List
  29. Attributes *NeighAttributes
  30. }
  31. // MarshalBinary marshals a NeighMessage into a byte slice.
  32. func (m *NeighMessage) MarshalBinary() ([]byte, error) {
  33. b := make([]byte, unix.SizeofNdMsg)
  34. nativeEndian.PutUint16(b[0:2], m.Family)
  35. // bytes 3 and 4 are padding
  36. nativeEndian.PutUint32(b[4:8], m.Index)
  37. nativeEndian.PutUint16(b[8:10], m.State)
  38. b[10] = m.Flags
  39. b[11] = m.Type
  40. if m.Attributes != nil {
  41. ae := netlink.NewAttributeEncoder()
  42. ae.ByteOrder = nativeEndian
  43. err := m.Attributes.encode(ae)
  44. if err != nil {
  45. return nil, err
  46. }
  47. a, err := ae.Encode()
  48. if err != nil {
  49. return nil, err
  50. }
  51. return append(b, a...), nil
  52. }
  53. return b, nil
  54. }
  55. // UnmarshalBinary unmarshals the contents of a byte slice into a NeighMessage.
  56. func (m *NeighMessage) UnmarshalBinary(b []byte) error {
  57. l := len(b)
  58. if l < unix.SizeofNdMsg {
  59. return errInvalidNeighMessage
  60. }
  61. m.Family = nativeEndian.Uint16(b[0:2])
  62. m.Index = nativeEndian.Uint32(b[4:8])
  63. m.State = nativeEndian.Uint16(b[8:10])
  64. m.Flags = b[10]
  65. m.Type = b[11]
  66. if l > unix.SizeofNdMsg {
  67. m.Attributes = &NeighAttributes{}
  68. ad, err := netlink.NewAttributeDecoder(b[unix.SizeofNdMsg:])
  69. if err != nil {
  70. return err
  71. }
  72. ad.ByteOrder = nativeEndian
  73. err = m.Attributes.decode(ad)
  74. if err != nil {
  75. return err
  76. }
  77. }
  78. return nil
  79. }
  80. // rtMessage is an empty method to sattisfy the Message interface.
  81. func (*NeighMessage) rtMessage() {}
  82. // NeighService is used to retrieve rtnetlink family information.
  83. type NeighService struct {
  84. c *Conn
  85. }
  86. // New creates a new interface using the LinkMessage information.
  87. func (l *NeighService) New(req *NeighMessage) error {
  88. flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
  89. _, err := l.c.Execute(req, unix.RTM_NEWNEIGH, flags)
  90. if err != nil {
  91. return err
  92. }
  93. return nil
  94. }
  95. // Delete removes an neighbor entry by index.
  96. func (l *NeighService) Delete(index uint32) error {
  97. req := &NeighMessage{}
  98. flags := netlink.Request | netlink.Acknowledge
  99. _, err := l.c.Execute(req, unix.RTM_DELNEIGH, flags)
  100. if err != nil {
  101. return err
  102. }
  103. return nil
  104. }
  105. // List retrieves all neighbors.
  106. func (l *NeighService) List() ([]NeighMessage, error) {
  107. req := NeighMessage{}
  108. flags := netlink.Request | netlink.Dump
  109. msgs, err := l.c.Execute(&req, unix.RTM_GETNEIGH, flags)
  110. if err != nil {
  111. return nil, err
  112. }
  113. neighs := make([]NeighMessage, len(msgs))
  114. for i := range msgs {
  115. neighs[i] = *msgs[i].(*NeighMessage)
  116. }
  117. return neighs, nil
  118. }
  119. // NeighCacheInfo contains neigh information
  120. type NeighCacheInfo struct {
  121. Confirmed uint32
  122. Used uint32
  123. Updated uint32
  124. RefCount uint32
  125. }
  126. // UnmarshalBinary unmarshals the contents of a byte slice into a NeighMessage.
  127. func (n *NeighCacheInfo) unmarshalBinary(b []byte) error {
  128. if len(b) != 16 {
  129. return fmt.Errorf("incorrect size, want: 16, got: %d", len(b))
  130. }
  131. n.Confirmed = nativeEndian.Uint32(b[0:4])
  132. n.Used = nativeEndian.Uint32(b[4:8])
  133. n.Updated = nativeEndian.Uint32(b[8:12])
  134. n.RefCount = nativeEndian.Uint32(b[12:16])
  135. return nil
  136. }
  137. // NeighAttributes contains all attributes for a neighbor.
  138. type NeighAttributes struct {
  139. Address net.IP // a neighbor cache n/w layer destination address
  140. LLAddress net.HardwareAddr // a neighbor cache link layer address
  141. CacheInfo *NeighCacheInfo // cache statistics
  142. IfIndex uint32
  143. }
  144. func (a *NeighAttributes) decode(ad *netlink.AttributeDecoder) error {
  145. for ad.Next() {
  146. switch ad.Type() {
  147. case unix.NDA_UNSPEC:
  148. // unused attribute
  149. case unix.NDA_DST:
  150. l := len(ad.Bytes())
  151. if l != 4 && l != 16 {
  152. return errInvalidNeighMessageAttr
  153. }
  154. a.Address = ad.Bytes()
  155. case unix.NDA_LLADDR:
  156. if len(ad.Bytes()) != 6 {
  157. return errInvalidNeighMessageAttr
  158. }
  159. a.LLAddress = ad.Bytes()
  160. case unix.NDA_CACHEINFO:
  161. a.CacheInfo = &NeighCacheInfo{}
  162. err := a.CacheInfo.unmarshalBinary(ad.Bytes())
  163. if err != nil {
  164. return err
  165. }
  166. case unix.NDA_IFINDEX:
  167. a.IfIndex = ad.Uint32()
  168. }
  169. }
  170. return nil
  171. }
  172. func (a *NeighAttributes) encode(ae *netlink.AttributeEncoder) error {
  173. ae.Uint16(unix.NDA_UNSPEC, 0)
  174. ae.Bytes(unix.NDA_DST, a.Address)
  175. ae.Bytes(unix.NDA_LLADDR, a.LLAddress)
  176. ae.Uint32(unix.NDA_IFINDEX, a.IfIndex)
  177. return nil
  178. }