conn.go 5.1 KB

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