func toIPVSService(vs *VirtualServer) (*libipvs.Service, error) {
	if vs == nil {
		return nil, errors.New("virtual server should not be empty")
	}
	ipvsSvc := &libipvs.Service{
		Address:   vs.Address,
		Protocol:  stringToProtocol(vs.Protocol),
		Port:      vs.Port,
		SchedName: vs.Scheduler,
		Flags:     uint32(vs.Flags),
		Timeout:   vs.Timeout,
	}
	if ip4 := vs.Address.To4(); ip4 != nil {
		ipvsSvc.AddressFamily = syscall.AF_INET
		ipvsSvc.Netmask = 0xffffffff
	} else {
		ipvsSvc.AddressFamily = syscall.AF_INET6
		ipvsSvc.Netmask = 128
	}
	return ipvsSvc, nil
}
toIPVSService converts a VirtualServer to the equivalent IPVS Service structure.
package ipvs
import (
	"fmt"
	"net"
	"strings"
	"sync"
	"syscall"
	"time"
	libipvs "github.com/moby/ipvs"
	"github.com/pkg/errors"
	"k8s.io/klog/v2"
	utilexec "k8s.io/utils/exec"
)
type runner struct {
	exec       utilexec.Interface
	ipvsHandle *libipvs.Handle
	mu         sync.Mutex  
}
type Protocol uint16
func New(exec utilexec.Interface) Interface {
	handle, err := libipvs.New("")
	if err != nil {
		klog.Errorf("IPVS interface can't be initialized, error: %v", err)
		return nil
	}
	return &runner{
		exec:       exec,
		ipvsHandle: handle,
	}
}
func (runner *runner) AddVirtualServer(vs *VirtualServer) error {
	svc, err := toIPVSService(vs)
	if err != nil {
		return errors.Wrap(err, "could not convert local virtual server to IPVS service")
	}
	runner.mu.Lock()
	defer runner.mu.Unlock()
	return runner.ipvsHandle.NewService(svc)
}
func (runner *runner) UpdateVirtualServer(vs *VirtualServer) error {
	svc, err := toIPVSService(vs)
	if err != nil {
		return errors.Wrap(err, "could not convert local virtual server to IPVS service")
	}
	runner.mu.Lock()
	defer runner.mu.Unlock()
	return runner.ipvsHandle.UpdateService(svc)
}
func (runner *runner) DeleteVirtualServer(vs *VirtualServer) error {
	svc, err := toIPVSService(vs)
	if err != nil {
		return errors.Wrap(err, "could not convert local virtual server to IPVS service")
	}
	runner.mu.Lock()
	defer runner.mu.Unlock()
	return runner.ipvsHandle.DelService(svc)
}
func (runner *runner) GetVirtualServer(vs *VirtualServer) (*VirtualServer, error) {
	svc, err := toIPVSService(vs)
	if err != nil {
		return nil, errors.Wrap(err, "could not convert local virtual server to IPVS service")
	}
	runner.mu.Lock()
	ipvsSvc, err := runner.ipvsHandle.GetService(svc)
	runner.mu.Unlock()
	if err != nil {
		return nil, errors.Wrap(err, "could not get IPVS service")
	}
	vServ, err := toVirtualServer(ipvsSvc)
	if err != nil {
		return nil, errors.Wrap(err, "could not convert IPVS service to local virtual server")
	}
	return vServ, nil
}
func (runner *runner) GetVirtualServers() ([]*VirtualServer, error) {
	runner.mu.Lock()
	ipvsSvcs, err := runner.ipvsHandle.GetServices()
	runner.mu.Unlock()
	if err != nil {
		return nil, errors.Wrap(err, "could not get IPVS services")
	}
	vss := make([]*VirtualServer, 0)
	for _, ipvsSvc := range ipvsSvcs {
		vs, err := toVirtualServer(ipvsSvc)
		if err != nil {
			return nil, errors.Wrap(err, "could not convert IPVS service to local virtual server")
		}
		vss = append(vss, vs)
	}
	return vss, nil
}
func (runner *runner) Flush() error {
	runner.mu.Lock()
	defer runner.mu.Unlock()
	return runner.ipvsHandle.Flush()
}
func (runner *runner) AddRealServer(vs *VirtualServer, rs *RealServer) error {
	svc, err := toIPVSService(vs)
	if err != nil {
		return errors.Wrap(err, "could not convert local virtual server to IPVS service")
	}
	dst, err := toIPVSDestination(rs)
	if err != nil {
		return errors.Wrap(err, "could not convert local real server to IPVS destination")
	}
	runner.mu.Lock()
	defer runner.mu.Unlock()
	return runner.ipvsHandle.NewDestination(svc, dst)
}
func (runner *runner) DeleteRealServer(vs *VirtualServer, rs *RealServer) error {
	svc, err := toIPVSService(vs)
	if err != nil {
		return errors.Wrap(err, "could not convert local virtual server to IPVS service")
	}
	dst, err := toIPVSDestination(rs)
	if err != nil {
		return errors.Wrap(err, "could not convert local real server to IPVS destination")
	}
	runner.mu.Lock()
	defer runner.mu.Unlock()
	return runner.ipvsHandle.DelDestination(svc, dst)
}
func (runner *runner) UpdateRealServer(vs *VirtualServer, rs *RealServer) error {
	svc, err := toIPVSService(vs)
	if err != nil {
		return errors.Wrap(err, "could not convert local virtual server to IPVS service")
	}
	dst, err := toIPVSDestination(rs)
	if err != nil {
		return errors.Wrap(err, "could not convert local real server to IPVS destination")
	}
	runner.mu.Lock()
	defer runner.mu.Unlock()
	return runner.ipvsHandle.UpdateDestination(svc, dst)
}
func (runner *runner) GetRealServers(vs *VirtualServer) ([]*RealServer, error) {
	svc, err := toIPVSService(vs)
	if err != nil {
		return nil, errors.Wrap(err, "could not convert local virtual server to IPVS service")
	}
	runner.mu.Lock()
	dsts, err := runner.ipvsHandle.GetDestinations(svc)
	runner.mu.Unlock()
	if err != nil {
		return nil, errors.Wrap(err, "could not get IPVS destination for service")
	}
	rss := make([]*RealServer, 0)
	for _, dst := range dsts {
		dst, err := toRealServer(dst)
		if err != nil {
			return nil, errors.Wrap(err, "could not convert IPVS destination to local real server")
		}
		rss = append(rss, dst)
	}
	return rss, nil
}
func (runner *runner) ConfigureTimeouts(tcpTimeout, tcpFinTimeout, udpTimeout time.Duration) error {
	ipvsConfig := &libipvs.Config{
		TimeoutTCP:    tcpTimeout,
		TimeoutTCPFin: tcpFinTimeout,
		TimeoutUDP:    udpTimeout,
	}
	return runner.ipvsHandle.SetConfig(ipvsConfig)
}
func toVirtualServer(svc *libipvs.Service) (*VirtualServer, error) {
	if svc == nil {
		return nil, errors.New("ipvs svc should not be empty")
	}
	vs := &VirtualServer{
		Address:   svc.Address,
		Port:      svc.Port,
		Scheduler: svc.SchedName,
		Protocol:  protocolToString(Protocol(svc.Protocol)),
		Timeout:   svc.Timeout,
	}
	if svc.Flags&FlagHashed == 0 {
		return nil, fmt.Errorf("flags of successfully created IPVS service should be >= %d since every service is hashed into the service table", FlagHashed)
	}
	vs.Flags = ServiceFlags(svc.Flags &^ uint32(FlagHashed))
	if vs.Address == nil {
		if svc.AddressFamily == syscall.AF_INET {
			vs.Address = net.IPv4zero
		} else {
			vs.Address = net.IPv6zero
		}
	}
	return vs, nil
}
func toRealServer(dst *libipvs.Destination) (*RealServer, error) {
	if dst == nil {
		return nil, errors.New("ipvs destination should not be empty")
	}
	return &RealServer{
		Address:      dst.Address,
		Port:         dst.Port,
		Weight:       dst.Weight,
		ActiveConn:   dst.ActiveConnections,
		InactiveConn: dst.InactiveConnections,
	}, nil
}