ipvs.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // +build linux
  2. package ipvs
  3. import (
  4. "net"
  5. "syscall"
  6. "time"
  7. "fmt"
  8. "github.com/vishvananda/netlink/nl"
  9. "github.com/vishvananda/netns"
  10. )
  11. const (
  12. netlinkRecvSocketsTimeout = 3 * time.Second
  13. netlinkSendSocketTimeout = 30 * time.Second
  14. )
  15. // Service defines an IPVS service in its entirety.
  16. type Service struct {
  17. // Virtual service address.
  18. Address net.IP
  19. Protocol uint16
  20. Port uint16
  21. FWMark uint32 // Firewall mark of the service.
  22. // Virtual service options.
  23. SchedName string
  24. Flags uint32
  25. Timeout uint32
  26. Netmask uint32
  27. AddressFamily uint16
  28. PEName string
  29. Stats SvcStats
  30. }
  31. // SvcStats defines an IPVS service statistics
  32. type SvcStats struct {
  33. Connections uint32
  34. PacketsIn uint32
  35. PacketsOut uint32
  36. BytesIn uint64
  37. BytesOut uint64
  38. CPS uint32
  39. BPSOut uint32
  40. PPSIn uint32
  41. PPSOut uint32
  42. BPSIn uint32
  43. }
  44. // Destination defines an IPVS destination (real server) in its
  45. // entirety.
  46. type Destination struct {
  47. Address net.IP
  48. Port uint16
  49. Weight int
  50. ConnectionFlags uint32
  51. AddressFamily uint16
  52. UpperThreshold uint32
  53. LowerThreshold uint32
  54. ActiveConnections int
  55. InactiveConnections int
  56. }
  57. // Handle provides a namespace specific ipvs handle to program ipvs
  58. // rules.
  59. type Handle struct {
  60. seq uint32
  61. sock *nl.NetlinkSocket
  62. }
  63. // New provides a new ipvs handle in the namespace pointed to by the
  64. // passed path. It will return a valid handle or an error in case an
  65. // error occurred while creating the handle.
  66. func New(path string) (*Handle, error) {
  67. setup()
  68. n := netns.None()
  69. if path != "" {
  70. var err error
  71. n, err = netns.GetFromPath(path)
  72. if err != nil {
  73. return nil, err
  74. }
  75. }
  76. defer n.Close()
  77. sock, err := nl.GetNetlinkSocketAt(n, netns.None(), syscall.NETLINK_GENERIC)
  78. if err != nil {
  79. return nil, err
  80. }
  81. // Add operation timeout to avoid deadlocks
  82. tv := syscall.NsecToTimeval(netlinkSendSocketTimeout.Nanoseconds())
  83. if err := sock.SetSendTimeout(&tv); err != nil {
  84. return nil, err
  85. }
  86. tv = syscall.NsecToTimeval(netlinkRecvSocketsTimeout.Nanoseconds())
  87. if err := sock.SetReceiveTimeout(&tv); err != nil {
  88. return nil, err
  89. }
  90. return &Handle{sock: sock}, nil
  91. }
  92. // Close closes the ipvs handle. The handle is invalid after Close
  93. // returns.
  94. func (i *Handle) Close() {
  95. if i.sock != nil {
  96. i.sock.Close()
  97. }
  98. }
  99. // NewService creates a new ipvs service in the passed handle.
  100. func (i *Handle) NewService(s *Service) error {
  101. return i.doCmd(s, nil, ipvsCmdNewService)
  102. }
  103. // IsServicePresent queries for the ipvs service in the passed handle.
  104. func (i *Handle) IsServicePresent(s *Service) bool {
  105. return nil == i.doCmd(s, nil, ipvsCmdGetService)
  106. }
  107. // UpdateService updates an already existing service in the passed
  108. // handle.
  109. func (i *Handle) UpdateService(s *Service) error {
  110. return i.doCmd(s, nil, ipvsCmdSetService)
  111. }
  112. // DelService deletes an already existing service in the passed
  113. // handle.
  114. func (i *Handle) DelService(s *Service) error {
  115. return i.doCmd(s, nil, ipvsCmdDelService)
  116. }
  117. // Flush deletes all existing services in the passed
  118. // handle.
  119. func (i *Handle) Flush() error {
  120. _, err := i.doCmdWithoutAttr(ipvsCmdFlush)
  121. return err
  122. }
  123. // NewDestination creates a new real server in the passed ipvs
  124. // service which should already be existing in the passed handle.
  125. func (i *Handle) NewDestination(s *Service, d *Destination) error {
  126. return i.doCmd(s, d, ipvsCmdNewDest)
  127. }
  128. // UpdateDestination updates an already existing real server in the
  129. // passed ipvs service in the passed handle.
  130. func (i *Handle) UpdateDestination(s *Service, d *Destination) error {
  131. return i.doCmd(s, d, ipvsCmdSetDest)
  132. }
  133. // DelDestination deletes an already existing real server in the
  134. // passed ipvs service in the passed handle.
  135. func (i *Handle) DelDestination(s *Service, d *Destination) error {
  136. return i.doCmd(s, d, ipvsCmdDelDest)
  137. }
  138. // GetServices returns an array of services configured on the Node
  139. func (i *Handle) GetServices() ([]*Service, error) {
  140. return i.doGetServicesCmd(nil)
  141. }
  142. // GetDestinations returns an array of Destinations configured for this Service
  143. func (i *Handle) GetDestinations(s *Service) ([]*Destination, error) {
  144. return i.doGetDestinationsCmd(s, nil)
  145. }
  146. // GetService gets details of a specific IPVS services, useful in updating statisics etc.,
  147. func (i *Handle) GetService(s *Service) (*Service, error) {
  148. res, err := i.doGetServicesCmd(s)
  149. if err != nil {
  150. return nil, err
  151. }
  152. // We are looking for exactly one service otherwise error out
  153. if len(res) != 1 {
  154. return nil, fmt.Errorf("Expected only one service obtained=%d", len(res))
  155. }
  156. return res[0], nil
  157. }