1/*
2Copyright 2017 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package ipvs
18
19import (
20	"net"
21	"strconv"
22	"strings"
23	"time"
24
25	"k8s.io/apimachinery/pkg/util/version"
26)
27
28// Interface is an injectable interface for running ipvs commands.  Implementations must be goroutine-safe.
29type Interface interface {
30	// Flush clears all virtual servers in system. return occurred error immediately.
31	Flush() error
32	// AddVirtualServer creates the specified virtual server.
33	AddVirtualServer(*VirtualServer) error
34	// UpdateVirtualServer updates an already existing virtual server.  If the virtual server does not exist, return error.
35	UpdateVirtualServer(*VirtualServer) error
36	// DeleteVirtualServer deletes the specified virtual server.  If the virtual server does not exist, return error.
37	DeleteVirtualServer(*VirtualServer) error
38	// Given a partial virtual server, GetVirtualServer will return the specified virtual server information in the system.
39	GetVirtualServer(*VirtualServer) (*VirtualServer, error)
40	// GetVirtualServers lists all virtual servers in the system.
41	GetVirtualServers() ([]*VirtualServer, error)
42	// AddRealServer creates the specified real server for the specified virtual server.
43	AddRealServer(*VirtualServer, *RealServer) error
44	// GetRealServers returns all real servers for the specified virtual server.
45	GetRealServers(*VirtualServer) ([]*RealServer, error)
46	// DeleteRealServer deletes the specified real server from the specified virtual server.
47	DeleteRealServer(*VirtualServer, *RealServer) error
48	// UpdateRealServer updates the specified real server from the specified virtual server.
49	UpdateRealServer(*VirtualServer, *RealServer) error
50	// ConfigureTimeouts is the equivalent to running "ipvsadm --set" to configure tcp, tcpfin and udp timeouts
51	ConfigureTimeouts(time.Duration, time.Duration, time.Duration) error
52}
53
54// VirtualServer is an user-oriented definition of an IPVS virtual server in its entirety.
55type VirtualServer struct {
56	Address   net.IP
57	Protocol  string
58	Port      uint16
59	Scheduler string
60	Flags     ServiceFlags
61	Timeout   uint32
62}
63
64// ServiceFlags is used to specify session affinity, ip hash etc.
65type ServiceFlags uint32
66
67const (
68	// FlagPersistent specify IPVS service session affinity
69	FlagPersistent = 0x1
70	// FlagHashed specify IPVS service hash flag
71	FlagHashed = 0x2
72)
73
74// IPVS required kernel modules.
75const (
76	// KernelModuleIPVS is the kernel module "ip_vs"
77	KernelModuleIPVS string = "ip_vs"
78	// KernelModuleIPVSRR is the kernel module "ip_vs_rr"
79	KernelModuleIPVSRR string = "ip_vs_rr"
80	// KernelModuleIPVSWRR is the kernel module "ip_vs_wrr"
81	KernelModuleIPVSWRR string = "ip_vs_wrr"
82	// KernelModuleIPVSSH is the kernel module "ip_vs_sh"
83	KernelModuleIPVSSH string = "ip_vs_sh"
84	// KernelModuleNfConntrackIPV4 is the module "nf_conntrack_ipv4"
85	KernelModuleNfConntrackIPV4 string = "nf_conntrack_ipv4"
86	// KernelModuleNfConntrack is the kernel module "nf_conntrack"
87	KernelModuleNfConntrack string = "nf_conntrack"
88)
89
90// Equal check the equality of virtual server.
91// We don't use struct == since it doesn't work because of slice.
92func (svc *VirtualServer) Equal(other *VirtualServer) bool {
93	return svc.Address.Equal(other.Address) &&
94		svc.Protocol == other.Protocol &&
95		svc.Port == other.Port &&
96		svc.Scheduler == other.Scheduler &&
97		svc.Flags == other.Flags &&
98		svc.Timeout == other.Timeout
99}
100
101func (svc *VirtualServer) String() string {
102	return net.JoinHostPort(svc.Address.String(), strconv.Itoa(int(svc.Port))) + "/" + svc.Protocol
103}
104
105// RealServer is an user-oriented definition of an IPVS real server in its entirety.
106type RealServer struct {
107	Address      net.IP
108	Port         uint16
109	Weight       int
110	ActiveConn   int
111	InactiveConn int
112}
113
114func (rs *RealServer) String() string {
115	return net.JoinHostPort(rs.Address.String(), strconv.Itoa(int(rs.Port)))
116}
117
118// Equal check the equality of real server.
119// We don't use struct == since it doesn't work because of slice.
120func (rs *RealServer) Equal(other *RealServer) bool {
121	return rs.Address.Equal(other.Address) &&
122		rs.Port == other.Port
123}
124
125// GetRequiredIPVSModules returns the required ipvs modules for the given linux kernel version.
126func GetRequiredIPVSModules(kernelVersion *version.Version) []string {
127	// "nf_conntrack_ipv4" has been removed since v4.19
128	// see https://github.com/torvalds/linux/commit/a0ae2562c6c4b2721d9fddba63b7286c13517d9f
129	if kernelVersion.LessThan(version.MustParseGeneric("4.19")) {
130		return []string{KernelModuleIPVS, KernelModuleIPVSRR, KernelModuleIPVSWRR, KernelModuleIPVSSH, KernelModuleNfConntrackIPV4}
131	}
132	return []string{KernelModuleIPVS, KernelModuleIPVSRR, KernelModuleIPVSWRR, KernelModuleIPVSSH, KernelModuleNfConntrack}
133
134}
135
136// IsRsGracefulTerminationNeeded returns true if protocol requires graceful termination for the stale connections
137func IsRsGracefulTerminationNeeded(proto string) bool {
138	return !strings.EqualFold(proto, "UDP") && !strings.EqualFold(proto, "SCTP")
139}
140