我希望在github.com/vishvananda/netlink/nl上实现一个类似函数的“ipvsadm --restore”。在github上搜索,我在libnetwork找到了一个有用的golang ipvs lib。
但是,它只为服务和目标提供新的/更新/删除功能。
我想要一个像“ipvsadm --restore”这样的函数。我不是ipvs / netlink专家,有没有人可以指出如何实现一个。
实际上,我试图像这样实现,但它不起作用。
package ipvs
import (
"net"
"syscall"
"fmt"
"os/exec"
"strings"
"github.com/vishvananda/netlink/nl"
"bytes"
"encoding/binary"
)
// Service defines an IPVS service in its entirety.
type Service struct {
// Virtual service address.
Address net.IP
Protocol uint16
Port uint16
FWMark uint32 // Firewall mark of the service.
// Virtual service options.
SchedName string
Flags uint32
Timeout uint32
Netmask uint32
AddressFamily uint16
PEName string
}
// Destination defines an IPVS destination (real server) in its
// entirety.
type Destination struct {
Address net.IP
Port uint16
Weight int
ConnectionFlags uint32
AddressFamily uint16
UpperThreshold uint32
LowerThreshold uint32
}
type ServiceDestination struct {
Service *Service
Destinations []*Destination
}
// Handle provides an ipvs handle to program ipvs rules.
type IPVSHandle struct {
ipvsFamily int
}
// NewIPVSHandler provides a new ipvs handler
func NewIPVSHandle() (*IPVSHandle, error) {
if out, err := exec.Command("modprobe", "-va", "ip_vs").CombinedOutput(); err != nil {
return nil, fmt.Errorf("Running modprobe ip_vs failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
}
ipvsFamily, err := getIPVSFamily()
if err != nil {
return nil, fmt.Errorf("Could not get ipvs family information from the kernel. It is possible that ipvs is not enabled in your kernel.")
}
return &IPVSHandle{ipvsFamily: ipvsFamily}, nil
}
func ( i *IPVSHandle) Restore(items []ServiceDestination)([][]byte, error) {
req := nl.NewNetlinkRequest(i.ipvsFamily, syscall.NLM_F_REPLACE)
req.AddData(&genlMsgHdr{cmd: ipvsCmdSetConfig, version: 1})
listAttr := nl.NewRtAttr(ipvsCmdAttrUnspec, nl.Uint16Attr(uint16(i.ipvsFamily)))
for _, item := range items {
itemAttr := nl.NewRtAttr(ipvsCmdAttrUnspec, nl.Uint16Attr(uint16(i.ipvsFamily)))
srvAttr := toServiceAttr(item.Service)
nl.NewRtAttrChild(itemAttr, ipvsCmdAttrService, srvAttr.Serialize())
for _, d := range item.Destinations {
nl.NewRtAttrChild(itemAttr, ipvsCmdAttrDest, fillDestinaton(d).Serialize())
}
nl.NewRtAttrChild(listAttr, ipvsCmdAttrUnspec, itemAttr.Serialize())
}
req.AddData(listAttr)
return req.Execute(syscall.NETLINK_GENERIC, 0)
}
func toServiceAttr(s *Service) *nl.RtAttr {
cmdAttr := nl.NewRtAttr(ipvsCmdAttrService, nil)
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrAddressFamily, nl.Uint16Attr(s.AddressFamily))
if s.FWMark != 0 {
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrFWMark, nl.Uint32Attr(s.FWMark))
} else {
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrProtocol, nl.Uint16Attr(s.Protocol))
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrAddress, rawIPData(s.Address))
// Port needs to be in network byte order.
portBuf := new(bytes.Buffer)
binary.Write(portBuf, binary.BigEndian, s.Port)
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrPort, portBuf.Bytes())
}
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrSchedName, nl.ZeroTerminated(s.SchedName))
if s.PEName != "" {
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrPEName, nl.ZeroTerminated(s.PEName))
}
f := &ipvsFlags{
flags: s.Flags,
mask: 0xFFFFFFFF,
}
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrFlags, f.Serialize())
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrTimeout, nl.Uint32Attr(s.Timeout))
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrNetmask, nl.Uint32Attr(s.Netmask))
return cmdAttr
}
func fillDestinaton(d *Destination) nl.NetlinkRequestData {
cmdAttr := nl.NewRtAttr(ipvsCmdAttrDest, nil)
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrAddress, rawIPData(d.Address))
// Port needs to be in network byte order.
portBuf := new(bytes.Buffer)
binary.Write(portBuf, binary.BigEndian, d.Port)
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrPort, portBuf.Bytes())
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrForwardingMethod, nl.Uint32Attr(d.ConnectionFlags&ConnectionFlagFwdMask))
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrWeight, nl.Uint32Attr(uint32(d.Weight)))
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrUpperThreshold, nl.Uint32Attr(d.UpperThreshold))
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrLowerThreshold, nl.Uint32Attr(d.LowerThreshold))
return cmdAttr
}