ipvs_linux.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // +build linux
  2. /*
  3. Copyright 2017 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package ipvs
  15. import (
  16. "errors"
  17. "fmt"
  18. "net"
  19. "strings"
  20. "sync"
  21. "syscall"
  22. "time"
  23. libipvs "github.com/docker/libnetwork/ipvs"
  24. "k8s.io/klog"
  25. utilexec "k8s.io/utils/exec"
  26. )
  27. // runner implements ipvs.Interface.
  28. type runner struct {
  29. exec utilexec.Interface
  30. ipvsHandle *libipvs.Handle
  31. mu sync.Mutex // Protect Netlink calls
  32. }
  33. // Protocol is the IPVS service protocol type
  34. type Protocol uint16
  35. // New returns a new Interface which will call ipvs APIs.
  36. func New(exec utilexec.Interface) Interface {
  37. handle, err := libipvs.New("")
  38. if err != nil {
  39. klog.Errorf("IPVS interface can't be initialized, error: %v", err)
  40. return nil
  41. }
  42. return &runner{
  43. exec: exec,
  44. ipvsHandle: handle,
  45. }
  46. }
  47. // AddVirtualServer is part of ipvs.Interface.
  48. func (runner *runner) AddVirtualServer(vs *VirtualServer) error {
  49. svc, err := toIPVSService(vs)
  50. if err != nil {
  51. return err
  52. }
  53. runner.mu.Lock()
  54. defer runner.mu.Unlock()
  55. return runner.ipvsHandle.NewService(svc)
  56. }
  57. // UpdateVirtualServer is part of ipvs.Interface.
  58. func (runner *runner) UpdateVirtualServer(vs *VirtualServer) error {
  59. svc, err := toIPVSService(vs)
  60. if err != nil {
  61. return err
  62. }
  63. runner.mu.Lock()
  64. defer runner.mu.Unlock()
  65. return runner.ipvsHandle.UpdateService(svc)
  66. }
  67. // DeleteVirtualServer is part of ipvs.Interface.
  68. func (runner *runner) DeleteVirtualServer(vs *VirtualServer) error {
  69. svc, err := toIPVSService(vs)
  70. if err != nil {
  71. return err
  72. }
  73. runner.mu.Lock()
  74. defer runner.mu.Unlock()
  75. return runner.ipvsHandle.DelService(svc)
  76. }
  77. // GetVirtualServer is part of ipvs.Interface.
  78. func (runner *runner) GetVirtualServer(vs *VirtualServer) (*VirtualServer, error) {
  79. svc, err := toIPVSService(vs)
  80. if err != nil {
  81. return nil, err
  82. }
  83. runner.mu.Lock()
  84. ipvsSvc, err := runner.ipvsHandle.GetService(svc)
  85. runner.mu.Unlock()
  86. if err != nil {
  87. return nil, err
  88. }
  89. vServ, err := toVirtualServer(ipvsSvc)
  90. if err != nil {
  91. return nil, err
  92. }
  93. return vServ, nil
  94. }
  95. // GetVirtualServers is part of ipvs.Interface.
  96. func (runner *runner) GetVirtualServers() ([]*VirtualServer, error) {
  97. runner.mu.Lock()
  98. ipvsSvcs, err := runner.ipvsHandle.GetServices()
  99. runner.mu.Unlock()
  100. if err != nil {
  101. return nil, err
  102. }
  103. vss := make([]*VirtualServer, 0)
  104. for _, ipvsSvc := range ipvsSvcs {
  105. vs, err := toVirtualServer(ipvsSvc)
  106. if err != nil {
  107. return nil, err
  108. }
  109. vss = append(vss, vs)
  110. }
  111. return vss, nil
  112. }
  113. // Flush is part of ipvs.Interface. Currently we delete IPVS services one by one
  114. func (runner *runner) Flush() error {
  115. runner.mu.Lock()
  116. defer runner.mu.Unlock()
  117. return runner.ipvsHandle.Flush()
  118. }
  119. // AddRealServer is part of ipvs.Interface.
  120. func (runner *runner) AddRealServer(vs *VirtualServer, rs *RealServer) error {
  121. svc, err := toIPVSService(vs)
  122. if err != nil {
  123. return err
  124. }
  125. dst, err := toIPVSDestination(rs)
  126. if err != nil {
  127. return err
  128. }
  129. runner.mu.Lock()
  130. defer runner.mu.Unlock()
  131. return runner.ipvsHandle.NewDestination(svc, dst)
  132. }
  133. // DeleteRealServer is part of ipvs.Interface.
  134. func (runner *runner) DeleteRealServer(vs *VirtualServer, rs *RealServer) error {
  135. svc, err := toIPVSService(vs)
  136. if err != nil {
  137. return err
  138. }
  139. dst, err := toIPVSDestination(rs)
  140. if err != nil {
  141. return err
  142. }
  143. runner.mu.Lock()
  144. defer runner.mu.Unlock()
  145. return runner.ipvsHandle.DelDestination(svc, dst)
  146. }
  147. func (runner *runner) UpdateRealServer(vs *VirtualServer, rs *RealServer) error {
  148. svc, err := toIPVSService(vs)
  149. if err != nil {
  150. return err
  151. }
  152. dst, err := toIPVSDestination(rs)
  153. if err != nil {
  154. return err
  155. }
  156. runner.mu.Lock()
  157. defer runner.mu.Unlock()
  158. return runner.ipvsHandle.UpdateDestination(svc, dst)
  159. }
  160. // GetRealServers is part of ipvs.Interface.
  161. func (runner *runner) GetRealServers(vs *VirtualServer) ([]*RealServer, error) {
  162. svc, err := toIPVSService(vs)
  163. if err != nil {
  164. return nil, err
  165. }
  166. runner.mu.Lock()
  167. dsts, err := runner.ipvsHandle.GetDestinations(svc)
  168. runner.mu.Unlock()
  169. if err != nil {
  170. return nil, err
  171. }
  172. rss := make([]*RealServer, 0)
  173. for _, dst := range dsts {
  174. dst, err := toRealServer(dst)
  175. // TODO: aggregate errors?
  176. if err != nil {
  177. return nil, err
  178. }
  179. rss = append(rss, dst)
  180. }
  181. return rss, nil
  182. }
  183. // ConfigureTimeouts is the equivalent to running "ipvsadm --set" to configure tcp, tcpfin and udp timeouts
  184. func (runner *runner) ConfigureTimeouts(tcpTimeout, tcpFinTimeout, udpTimeout time.Duration) error {
  185. ipvsConfig := &libipvs.Config{
  186. TimeoutTCP: tcpTimeout,
  187. TimeoutTCPFin: tcpFinTimeout,
  188. TimeoutUDP: udpTimeout,
  189. }
  190. return runner.ipvsHandle.SetConfig(ipvsConfig)
  191. }
  192. // toVirtualServer converts an IPVS Service to the equivalent VirtualServer structure.
  193. func toVirtualServer(svc *libipvs.Service) (*VirtualServer, error) {
  194. if svc == nil {
  195. return nil, errors.New("ipvs svc should not be empty")
  196. }
  197. vs := &VirtualServer{
  198. Address: svc.Address,
  199. Port: svc.Port,
  200. Scheduler: svc.SchedName,
  201. Protocol: protocolToString(Protocol(svc.Protocol)),
  202. Timeout: svc.Timeout,
  203. }
  204. // Test Flags >= 0x2, valid Flags ranges [0x2, 0x3]
  205. if svc.Flags&FlagHashed == 0 {
  206. return nil, fmt.Errorf("Flags of successfully created IPVS service should be >= %d since every service is hashed into the service table", FlagHashed)
  207. }
  208. // Sub Flags to 0x2
  209. // 011 -> 001, 010 -> 000
  210. vs.Flags = ServiceFlags(svc.Flags &^ uint32(FlagHashed))
  211. if vs.Address == nil {
  212. if svc.AddressFamily == syscall.AF_INET {
  213. vs.Address = net.IPv4zero
  214. } else {
  215. vs.Address = net.IPv6zero
  216. }
  217. }
  218. return vs, nil
  219. }
  220. // toRealServer converts an IPVS Destination to the equivalent RealServer structure.
  221. func toRealServer(dst *libipvs.Destination) (*RealServer, error) {
  222. if dst == nil {
  223. return nil, errors.New("ipvs destination should not be empty")
  224. }
  225. return &RealServer{
  226. Address: dst.Address,
  227. Port: dst.Port,
  228. Weight: dst.Weight,
  229. ActiveConn: dst.ActiveConnections,
  230. InactiveConn: dst.InactiveConnections,
  231. }, nil
  232. }
  233. // toIPVSService converts a VirtualServer to the equivalent IPVS Service structure.
  234. func toIPVSService(vs *VirtualServer) (*libipvs.Service, error) {
  235. if vs == nil {
  236. return nil, errors.New("virtual server should not be empty")
  237. }
  238. ipvsSvc := &libipvs.Service{
  239. Address: vs.Address,
  240. Protocol: stringToProtocol(vs.Protocol),
  241. Port: vs.Port,
  242. SchedName: vs.Scheduler,
  243. Flags: uint32(vs.Flags),
  244. Timeout: vs.Timeout,
  245. }
  246. if ip4 := vs.Address.To4(); ip4 != nil {
  247. ipvsSvc.AddressFamily = syscall.AF_INET
  248. ipvsSvc.Netmask = 0xffffffff
  249. } else {
  250. ipvsSvc.AddressFamily = syscall.AF_INET6
  251. ipvsSvc.Netmask = 128
  252. }
  253. return ipvsSvc, nil
  254. }
  255. // toIPVSDestination converts a RealServer to the equivalent IPVS Destination structure.
  256. func toIPVSDestination(rs *RealServer) (*libipvs.Destination, error) {
  257. if rs == nil {
  258. return nil, errors.New("real server should not be empty")
  259. }
  260. return &libipvs.Destination{
  261. Address: rs.Address,
  262. Port: rs.Port,
  263. Weight: rs.Weight,
  264. }, nil
  265. }
  266. // stringToProtocolType returns the protocol type for the given name
  267. func stringToProtocol(protocol string) uint16 {
  268. switch strings.ToLower(protocol) {
  269. case "tcp":
  270. return uint16(syscall.IPPROTO_TCP)
  271. case "udp":
  272. return uint16(syscall.IPPROTO_UDP)
  273. case "sctp":
  274. return uint16(syscall.IPPROTO_SCTP)
  275. }
  276. return uint16(0)
  277. }
  278. // protocolTypeToString returns the name for the given protocol.
  279. func protocolToString(proto Protocol) string {
  280. switch proto {
  281. case syscall.IPPROTO_TCP:
  282. return "TCP"
  283. case syscall.IPPROTO_UDP:
  284. return "UDP"
  285. case syscall.IPPROTO_SCTP:
  286. return "SCTP"
  287. }
  288. return ""
  289. }