conn.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. package rtnetlink
  2. import (
  3. "encoding"
  4. "time"
  5. "github.com/jsimonetti/rtnetlink/internal/unix"
  6. "github.com/mdlayher/netlink"
  7. )
  8. // A Conn is a route netlink connection. A Conn can be used to send and
  9. // receive route netlink messages to and from netlink.
  10. type Conn struct {
  11. c conn
  12. Link *LinkService
  13. Address *AddressService
  14. Route *RouteService
  15. Neigh *NeighService
  16. }
  17. var _ conn = &netlink.Conn{}
  18. // A conn is a netlink connection, which can be swapped for tests.
  19. type conn interface {
  20. Close() error
  21. Send(m netlink.Message) (netlink.Message, error)
  22. Receive() ([]netlink.Message, error)
  23. Execute(m netlink.Message) ([]netlink.Message, error)
  24. SetOption(option netlink.ConnOption, enable bool) error
  25. SetReadDeadline(t time.Time) error
  26. }
  27. // Dial dials a route netlink connection. Config specifies optional
  28. // configuration for the underlying netlink connection. If config is
  29. // nil, a default configuration will be used.
  30. func Dial(config *netlink.Config) (*Conn, error) {
  31. c, err := netlink.Dial(unix.NETLINK_ROUTE, config)
  32. if err != nil {
  33. return nil, err
  34. }
  35. return newConn(c), nil
  36. }
  37. // newConn creates a Conn that wraps an existing *netlink.Conn for
  38. // rtnetlink communications. It is used for testing.
  39. func newConn(c conn) *Conn {
  40. rtc := &Conn{
  41. c: c,
  42. }
  43. rtc.Link = &LinkService{c: rtc}
  44. rtc.Address = &AddressService{c: rtc}
  45. rtc.Route = &RouteService{c: rtc}
  46. rtc.Neigh = &NeighService{c: rtc}
  47. return rtc
  48. }
  49. // Close closes the connection.
  50. func (c *Conn) Close() error {
  51. return c.c.Close()
  52. }
  53. // SetOption enables or disables a netlink socket option for the Conn.
  54. func (c *Conn) SetOption(option netlink.ConnOption, enable bool) error {
  55. return c.c.SetOption(option, enable)
  56. }
  57. // SetReadDeadline sets the read deadline associated with the connection.
  58. func (c *Conn) SetReadDeadline(t time.Time) error {
  59. return c.c.SetReadDeadline(t)
  60. }
  61. // Send sends a single Message to netlink, wrapping it in a netlink.Message
  62. // using the specified generic netlink family and flags. On success, Send
  63. // returns a copy of the netlink.Message with all parameters populated, for
  64. // later validation.
  65. func (c *Conn) Send(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
  66. nm := netlink.Message{
  67. Header: netlink.Header{
  68. Type: netlink.HeaderType(family),
  69. Flags: flags,
  70. },
  71. }
  72. mb, err := m.MarshalBinary()
  73. if err != nil {
  74. return netlink.Message{}, err
  75. }
  76. nm.Data = mb
  77. reqnm, err := c.c.Send(nm)
  78. if err != nil {
  79. return netlink.Message{}, err
  80. }
  81. return reqnm, nil
  82. }
  83. // Receive receives one or more Messages from netlink. The netlink.Messages
  84. // used to wrap each Message are available for later validation.
  85. func (c *Conn) Receive() ([]Message, []netlink.Message, error) {
  86. msgs, err := c.c.Receive()
  87. if err != nil {
  88. return nil, nil, err
  89. }
  90. rtmsgs, err := unpackMessages(msgs)
  91. if err != nil {
  92. return nil, nil, err
  93. }
  94. return rtmsgs, msgs, nil
  95. }
  96. // Execute sends a single Message to netlink using Send, receives one or more
  97. // replies using Receive, and then checks the validity of the replies against
  98. // the request using netlink.Validate.
  99. //
  100. // Execute acquires a lock for the duration of the function call which blocks
  101. // concurrent calls to Send and Receive, in order to ensure consistency between
  102. // generic netlink request/reply messages.
  103. //
  104. // See the documentation of Send, Receive, and netlink.Validate for details
  105. // about each function.
  106. func (c *Conn) Execute(m Message, family uint16, flags netlink.HeaderFlags) ([]Message, error) {
  107. nm, err := packMessage(m, family, flags)
  108. if err != nil {
  109. return nil, err
  110. }
  111. msgs, err := c.c.Execute(nm)
  112. if err != nil {
  113. return nil, err
  114. }
  115. return unpackMessages(msgs)
  116. }
  117. // Message is the interface used for passing around different kinds of rtnetlink messages
  118. type Message interface {
  119. encoding.BinaryMarshaler
  120. encoding.BinaryUnmarshaler
  121. rtMessage()
  122. }
  123. // packMessage packs a rtnetlink Message into a netlink.Message with the
  124. // appropriate rtnetlink family and netlink flags.
  125. func packMessage(m Message, family uint16, flags netlink.HeaderFlags) (netlink.Message, error) {
  126. nm := netlink.Message{
  127. Header: netlink.Header{
  128. Type: netlink.HeaderType(family),
  129. Flags: flags,
  130. },
  131. }
  132. mb, err := m.MarshalBinary()
  133. if err != nil {
  134. return netlink.Message{}, err
  135. }
  136. nm.Data = mb
  137. return nm, nil
  138. }
  139. // unpackMessages unpacks rtnetlink Messages from a slice of netlink.Messages.
  140. func unpackMessages(msgs []netlink.Message) ([]Message, error) {
  141. lmsgs := make([]Message, 0, len(msgs))
  142. for _, nm := range msgs {
  143. var m Message
  144. switch nm.Header.Type {
  145. case unix.RTM_GETLINK, unix.RTM_NEWLINK, unix.RTM_DELLINK:
  146. m = &LinkMessage{}
  147. case unix.RTM_GETADDR, unix.RTM_NEWADDR, unix.RTM_DELADDR:
  148. m = &AddressMessage{}
  149. case unix.RTM_GETROUTE, unix.RTM_NEWROUTE, unix.RTM_DELROUTE:
  150. m = &RouteMessage{}
  151. case unix.RTM_GETNEIGH, unix.RTM_NEWNEIGH, unix.RTM_DELNEIGH:
  152. m = &NeighMessage{}
  153. default:
  154. continue
  155. }
  156. if err := (m).UnmarshalBinary(nm.Data); err != nil {
  157. return nil, err
  158. }
  159. lmsgs = append(lmsgs, m)
  160. }
  161. return lmsgs, nil
  162. }