Created
March 27, 2020 21:35
-
-
Save rikatz/807c68ebbd73cba7c2e759a5586e366b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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