pkg/skoop/netstack/ipvs.go (129 lines of code) (raw):
package netstack
import (
"flag"
"fmt"
"strconv"
"strings"
"github.com/alibaba/kubeskoop/pkg/skoop/model"
"github.com/pkg/errors"
)
type RealServer struct {
Service string `json:"s,omitempty"`
IP string `json:"ip"`
Port uint16 `json:"p"`
Masquerade bool `json:"m"`
Weight int `json:"w"`
}
type IPVSService struct {
Protocol model.Protocol `json:"pro"`
IP string `json:"ip"`
Port uint16 `json:"p"`
Scheduler string `json:"s"`
RS []RealServer `json:"r"`
}
func (s *IPVSService) Service() string {
return fmt.Sprintf("%s:%s:%d", s.Protocol, s.IP, s.Port)
}
type IPVS struct {
services map[string]*IPVSService
}
func (ipvs *IPVS) GetService(proto model.Protocol, ip string, port uint16) *IPVSService {
key := fmt.Sprintf("%s:%s:%d", strings.ToLower(string(proto)), ip, port)
return ipvs.services[key]
}
func parseOneLine(ipvs *IPVS, line string) error {
var (
addService bool
tcpService string
udpService string
scheduler string
addServer bool
realServer string
masquerading bool
weight string
persistent string
)
ipvsFlags := flag.NewFlagSet("ipvs", flag.ContinueOnError)
ipvsFlags.BoolVar(&addService, "A", false, "")
ipvsFlags.StringVar(&tcpService, "t", "", "")
ipvsFlags.StringVar(&udpService, "u", "", "")
ipvsFlags.StringVar(&scheduler, "s", "", "")
ipvsFlags.BoolVar(&addServer, "a", false, "")
ipvsFlags.StringVar(&realServer, "r", "", "")
ipvsFlags.BoolVar(&masquerading, "m", false, "")
ipvsFlags.StringVar(&weight, "w", "", "")
ipvsFlags.StringVar(&persistent, "p", "", "")
if err := ipvsFlags.Parse(strings.Fields(line)); err != nil {
return errors.Wrapf(err, "error parse ipvs rule %s", line)
}
if !addServer && !addService {
return fmt.Errorf("unknown ipvs action")
}
var protocol model.Protocol
var service string
if udpService != "" {
protocol = model.UDP
service = udpService
} else {
protocol = model.TCP
service = tcpService
}
arr := strings.Split(service, ":")
serviceIP := arr[0]
servicePort, err := strconv.Atoi(arr[1])
if err != nil {
return err
}
if addService {
svc := &IPVSService{
Protocol: protocol,
IP: serviceIP,
Port: uint16(servicePort),
Scheduler: scheduler,
}
ipvs.services[svc.Service()] = svc
return nil
}
if addServer {
weightInt, _ := strconv.Atoi(weight)
arr := strings.Split(realServer, ":")
serverIP := arr[0]
serverPort, err := strconv.Atoi(arr[1])
if err != nil {
return err
}
backend := RealServer{
IP: serverIP,
Port: uint16(serverPort),
Masquerade: masquerading,
Weight: weightInt,
}
serviceName := fmt.Sprintf("%s:%s", protocol, service)
svc, ok := ipvs.services[serviceName]
if !ok {
return fmt.Errorf("service not exists")
}
svc.RS = append(svc.RS, backend)
return nil
}
return nil
}
func ParseIPVS(dump []string) (*IPVS, error) {
ipvs := &IPVS{
services: make(map[string]*IPVSService),
}
for _, line := range dump {
if line == "" {
continue
}
if err := parseOneLine(ipvs, line); err != nil {
return nil, err
}
}
return ipvs, nil
}
func NewIPVS(services map[string]*IPVSService) *IPVS {
return &IPVS{
services: services,
}
}