Skip to content

Instantly share code, notes, and snippets.

@rikatz
Created March 27, 2020 21:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rikatz/807c68ebbd73cba7c2e759a5586e366b to your computer and use it in GitHub Desktop.
Save rikatz/807c68ebbd73cba7c2e759a5586e366b to your computer and use it in GitHub Desktop.
package main
import (
"errors"
"fmt"
"net"
"strings"
"sync"
"syscall"
utilexec "k8s.io/utils/exec"
libipvs "github.com/moby/ipvs"
)
// VirtualServer is an user-oriented definition of an IPVS virtual server in its entirety.
type VirtualServer struct {
Address net.IP
Protocol string
Port uint16
Scheduler string
Flags ServiceFlags
Timeout uint32
}
type ServiceFlags uint32
// RealServer is an user-oriented definition of an IPVS real server in its entirety.
type RealServer struct {
Address net.IP
Port uint16
Weight int
ActiveConn int
InactiveConn int
}
type runner struct {
exec utilexec.Interface
ipvsHandle *libipvs.Handle
mu sync.Mutex // Protect Netlink calls
}
func main() {
handle, err := libipvs.New("")
runnerExec := &runner{
ipvsHandle: handle,
}
if err != nil {
fmt.Printf("IPVS interface can't be initialized, error: %v", err)
}
vs := &VirtualServer{
Address: net.ParseIP("fd00:10:96::a"),
Protocol: "UDP",
Port: 53,
Scheduler: "lc",
Flags: 0,
Timeout: 0,
}
svc, err := toIPVSService(vs)
if err != nil {
fmt.Errorf("Error TO IPVS Service: %v", err)
}
dsts, err := runnerExec.ipvsHandle.GetDestinations(svc)
if err != nil {
fmt.Errorf("Error Get Destinations: %v", err)
}
rss := make([]*RealServer, 0)
for _, dst := range dsts {
dst, err := toRealServer(dst)
// TODO: aggregate errors?
if err != nil {
fmt.Errorf("Error To Real Server: %v", err)
}
fmt.Printf("%v\n", dst)
rss = append(rss, dst)
}
}
// toRealServer converts an IPVS Destination to the equivalent RealServer structure.
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
}
// toIPVSService converts a VirtualServer to the equivalent IPVS Service structure.
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
}
// stringToProtocolType returns the protocol type for the given name
func stringToProtocol(protocol string) uint16 {
switch strings.ToLower(protocol) {
case "tcp":
return uint16(syscall.IPPROTO_TCP)
case "udp":
return uint16(syscall.IPPROTO_UDP)
case "sctp":
return uint16(syscall.IPPROTO_SCTP)
}
return uint16(0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment