package libipvs import ( "fmt" "net" "syscall" "github.com/hkwi/nlgo" ) type AddressFamily uint16 func (af AddressFamily) String() string { switch af { case syscall.AF_INET: return "inet" case syscall.AF_INET6: return "inet6" default: return fmt.Sprintf("%d", af) } } type Protocol uint16 func (p Protocol) String() string { switch p { case syscall.IPPROTO_TCP: return "tcp" case syscall.IPPROTO_UDP: return "udp" case syscall.IPPROTO_SCTP: return "sctp" default: return fmt.Sprintf("%d", p) } } type Flags struct { Flags uint32 Mask uint32 } // Service defines an IPVS service in its entirety. type Service struct { // Virtual service address. Address net.IP Protocol Protocol Port uint16 FWMark uint32 // Firewall mark of the service. // Virtual service options. SchedName string Flags Flags Timeout uint32 Netmask uint32 AddressFamily AddressFamily PEName string Stats Stats } // Destination defines an IPVS destination (real server) in its // entirety. type Destination struct { AddressFamily AddressFamily Address net.IP Port uint16 FwdMethod FwdMethod Weight uint32 UThresh uint32 LThresh uint32 ActiveConns uint32 InactConns uint32 PersistConns uint32 Stats Stats } type Stats struct { Connections uint32 PacketsIn uint32 PacketsOut uint32 BytesIn uint64 BytesOut uint64 CPS uint32 PPSIn uint32 PPSOut uint32 BPSIn uint32 BPSOut uint32 } // Pack Service to a set of nlattrs. // If full is given, include service settings, otherwise only the identifying fields are given. func (self *Service) attrs(full bool) nlgo.AttrSlice { var attrs nlgo.AttrSlice if self.FWMark != 0 { attrs = append(attrs, nlattr(IPVS_SVC_ATTR_AF, nlgo.U16(self.AddressFamily)), nlattr(IPVS_SVC_ATTR_FWMARK, nlgo.U32(self.FWMark)), ) } else if self.Protocol != 0 && self.Address != nil && self.Port != 0 { attrs = append(attrs, nlattr(IPVS_SVC_ATTR_AF, nlgo.U16(self.AddressFamily)), nlattr(IPVS_SVC_ATTR_PROTOCOL, nlgo.U16(self.Protocol)), nlattr(IPVS_SVC_ATTR_ADDR, packAddr(self.AddressFamily, self.Address)), nlattr(IPVS_SVC_ATTR_PORT, packPort(self.Port)), ) } else { panic("Incomplete service id fields") } if full { attrs = append(attrs, nlattr(IPVS_SVC_ATTR_SCHED_NAME, nlgo.NulString(self.SchedName)), nlattr(IPVS_SVC_ATTR_FLAGS, pack(&self.Flags)), nlattr(IPVS_SVC_ATTR_TIMEOUT, nlgo.U32(self.Timeout)), nlattr(IPVS_SVC_ATTR_NETMASK, nlgo.U32(self.Netmask)), ) } return attrs } // Dump Dest as nl attrs, using the Af of the corresponding Service. // If full, includes Dest setting attrs, otherwise only identifying attrs. func (self *Destination) attrs(full bool) nlgo.AttrSlice { var attrs nlgo.AttrSlice attrs = append(attrs, nlattr(IPVS_DEST_ATTR_ADDR_FAMILY, nlgo.U16(self.AddressFamily)), nlattr(IPVS_DEST_ATTR_ADDR, packAddr(self.AddressFamily, self.Address)), nlattr(IPVS_DEST_ATTR_PORT, packPort(self.Port)), ) if full { attrs = append(attrs, nlattr(IPVS_DEST_ATTR_FWD_METHOD, nlgo.U32(self.FwdMethod)), nlattr(IPVS_DEST_ATTR_WEIGHT, nlgo.U32(self.Weight)), nlattr(IPVS_DEST_ATTR_U_THRESH, nlgo.U32(self.UThresh)), nlattr(IPVS_DEST_ATTR_L_THRESH, nlgo.U32(self.LThresh)), ) } return attrs } type FwdMethod uint32 func (self FwdMethod) String() string { switch value := (uint32(self) & IP_VS_CONN_F_FWD_MASK); value { case IP_VS_CONN_F_MASQ: return "masq" case IP_VS_CONN_F_LOCALNODE: return "localnode" case IP_VS_CONN_F_TUNNEL: return "tunnel" case IP_VS_CONN_F_DROUTE: return "droute" case IP_VS_CONN_F_BYPASS: return "bypass" default: return fmt.Sprintf("%#04x", value) } } func ParseFwdMethod(value string) (FwdMethod, error) { switch value { case "masq": return IP_VS_CONN_F_MASQ, nil case "tunnel": return IP_VS_CONN_F_TUNNEL, nil case "droute": return IP_VS_CONN_F_DROUTE, nil default: return 0, fmt.Errorf("Invalid FwdMethod: %s", value) } } type Version uint32 func (version Version) String() string { return fmt.Sprintf("%d.%d.%d", (version>>16)&0xFF, (version>>8)&0xFF, (version>>0)&0xFF, ) } type Info struct { Version Version ConnTabSize uint32 }