Merge pull request #615 from mccv1r0/pr602

Allow multiple routes to be added for the same prefix
This commit is contained in:
Casey Callendrello 2021-05-05 11:33:55 -04:00 committed by GitHub
commit 8de0287741
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1133 additions and 158 deletions

5
go.mod
View File

@ -19,6 +19,7 @@ require (
github.com/onsi/gomega v1.10.3 github.com/onsi/gomega v1.10.3
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.8.1 // indirect
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5
golang.org/x/sys v0.0.0-20210324051608-47abb6519492 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f // indirect
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0
) )

8
go.sum
View File

@ -515,12 +515,14 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 h1:cPXZWzzG0NllBLdjWoD1nDfaqu98YMv+OneaKc8sPOA= github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA852UkGH42H+Oee69djmxS3ANzl2b/JtT1YiA=
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@ -696,6 +698,8 @@ golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg= golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0 h1:g9s1Ppvvun/fI+BptTMj909BBIcGrzQ32k9FNlcevOE=
golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@ -113,11 +113,14 @@ func ConfigureIface(ifName string, res *current.Result) error {
gw = v6gw gw = v6gw
} }
} }
if err = ip.AddRoute(&r.Dst, gw, link); err != nil { route := netlink.Route{
// we skip over duplicate routes as we assume the first one wins Dst: &r.Dst,
if !os.IsExist(err) { LinkIndex: link.Attrs().Index,
return fmt.Errorf("failed to add route '%v via %v dev %v': %v", r.Dst, gw, ifName, err) Gw: gw,
} }
if err = netlink.RouteAddEcmp(&route); err != nil {
return fmt.Errorf("failed to add route '%v via %v dev %v': %v", r.Dst, gw, ifName, err)
} }
} }

View File

@ -176,6 +176,12 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize()) options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize())
options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab)) options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab))
options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab)) options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab))
if htb.Rate >= uint64(1<<32) {
options.AddRtAttr(nl.TCA_HTB_RATE64, nl.Uint64Attr(htb.Rate))
}
if htb.Ceil >= uint64(1<<32) {
options.AddRtAttr(nl.TCA_HTB_CEIL64, nl.Uint64Attr(htb.Ceil))
}
case "hfsc": case "hfsc":
hfsc := class.(*HfscClass) hfsc := class.(*HfscClass)
opt := nl.HfscCopt{} opt := nl.HfscCopt{}
@ -306,6 +312,10 @@ func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, erro
htb.Quantum = opt.Quantum htb.Quantum = opt.Quantum
htb.Level = opt.Level htb.Level = opt.Level
htb.Prio = opt.Prio htb.Prio = opt.Prio
case nl.TCA_HTB_RATE64:
htb.Rate = native.Uint64(datum.Value[0:8])
case nl.TCA_HTB_CEIL64:
htb.Ceil = native.Uint64(datum.Value[0:8])
} }
} }
return detailed, nil return detailed, nil

View File

@ -27,6 +27,18 @@ type DevlinkDevice struct {
Attrs DevlinkDevAttrs Attrs DevlinkDevAttrs
} }
// DevlinkPort represents port and its attributes
type DevlinkPort struct {
BusName string
DeviceName string
PortIndex uint32
PortType uint16
NetdeviceName string
NetdevIfIndex uint32
RdmaDeviceName string
PortFlavour uint16
}
func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) { func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
devices := make([]*DevlinkDevice, 0, len(msgs)) devices := make([]*DevlinkDevice, 0, len(msgs))
for _, m := range msgs { for _, m := range msgs {
@ -270,3 +282,112 @@ func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error
func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error { func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode) return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode)
} }
func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
for _, a := range attrs {
switch a.Attr.Type {
case nl.DEVLINK_ATTR_BUS_NAME:
port.BusName = string(a.Value)
case nl.DEVLINK_ATTR_DEV_NAME:
port.DeviceName = string(a.Value)
case nl.DEVLINK_ATTR_PORT_INDEX:
port.PortIndex = native.Uint32(a.Value)
case nl.DEVLINK_ATTR_PORT_TYPE:
port.PortType = native.Uint16(a.Value)
case nl.DEVLINK_ATTR_PORT_NETDEV_NAME:
port.NetdeviceName = string(a.Value)
case nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX:
port.NetdevIfIndex = native.Uint32(a.Value)
case nl.DEVLINK_ATTR_PORT_IBDEV_NAME:
port.RdmaDeviceName = string(a.Value)
case nl.DEVLINK_ATTR_PORT_FLAVOUR:
port.PortFlavour = native.Uint16(a.Value)
}
}
return nil
}
func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
ports := make([]*DevlinkPort, 0, len(msgs))
for _, m := range msgs {
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
if err != nil {
return nil, err
}
port := &DevlinkPort{}
if err = port.parseAttributes(attrs); err != nil {
return nil, err
}
ports = append(ports, port)
}
return ports, nil
}
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
// otherwise returns an error code.
func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
if err != nil {
return nil, err
}
msg := &nl.Genlmsg{
Command: nl.DEVLINK_CMD_PORT_GET,
Version: nl.GENL_DEVLINK_VERSION,
}
req := h.newNetlinkRequest(int(f.ID),
unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
req.AddData(msg)
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
ports, err := parseDevLinkAllPortList(msgs)
if err != nil {
return nil, err
}
return ports, nil
}
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
// otherwise returns an error code.
func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
return pkgHandle.DevLinkGetAllPortList()
}
func parseDevlinkPortMsg(msgs [][]byte) (*DevlinkPort, error) {
m := msgs[0]
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
if err != nil {
return nil, err
}
port := &DevlinkPort{}
if err = port.parseAttributes(attrs); err != nil {
return nil, err
}
return port, nil
}
// DevLinkGetPortByIndexprovides a pointer to devlink device and nil error,
// otherwise returns an error code.
func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_GET, Bus, Device)
if err != nil {
return nil, err
}
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
port, err := parseDevlinkPortMsg(respmsg)
return port, err
}
// DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
// otherwise returns an error code.
func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex)
}

View File

@ -36,6 +36,7 @@ type U32 struct {
ClassId uint32 ClassId uint32
Divisor uint32 // Divisor MUST be power of 2. Divisor uint32 // Divisor MUST be power of 2.
Hash uint32 Hash uint32
Link uint32
RedirIndex int RedirIndex int
Sel *TcU32Sel Sel *TcU32Sel
Actions []Action Actions []Action
@ -225,6 +226,9 @@ func (h *Handle) filterModify(filter Filter, flags int) error {
if filter.Hash != 0 { if filter.Hash != 0 {
options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash)) options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash))
} }
if filter.Link != 0 {
options.AddRtAttr(nl.TCA_U32_LINK, nl.Uint32Attr(filter.Link))
}
actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil) actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil)
// backwards compatibility // backwards compatibility
if filter.RedirIndex != 0 { if filter.RedirIndex != 0 {
@ -666,6 +670,8 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
u32.Divisor = native.Uint32(datum.Value) u32.Divisor = native.Uint32(datum.Value)
case nl.TCA_U32_HASH: case nl.TCA_U32_HASH:
u32.Hash = native.Uint32(datum.Value) u32.Hash = native.Uint32(datum.Value)
case nl.TCA_U32_LINK:
u32.Link = native.Uint32(datum.Value)
} }
} }
return detailed, nil return detailed, nil

View File

@ -21,6 +21,22 @@ type Handle struct {
lookupByDump bool lookupByDump bool
} }
// SetSocketTimeout configures timeout for default netlink sockets
func SetSocketTimeout(to time.Duration) error {
if to < time.Microsecond {
return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond)
}
nl.SocketTimeoutTv = unix.NsecToTimeval(to.Nanoseconds())
return nil
}
// GetSocketTimeout returns the timeout value used by default netlink sockets
func GetSocketTimeout() time.Duration {
nsec := unix.TimevalToNsec(nl.SocketTimeoutTv)
return time.Duration(nsec) * time.Nanosecond
}
// SupportsNetlinkFamily reports whether the passed netlink family is supported by this Handle // SupportsNetlinkFamily reports whether the passed netlink family is supported by this Handle
func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool { func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool {
_, ok := h.sockets[nlFamily] _, ok := h.sockets[nlFamily]

View File

@ -237,6 +237,10 @@ func (h *Handle) RouteAdd(route *Route) error {
return ErrNotImplemented return ErrNotImplemented
} }
func (h *Handle) RouteAppend(route *Route) error {
return ErrNotImplemented
}
func (h *Handle) RouteDel(route *Route) error { func (h *Handle) RouteDel(route *Route) error {
return ErrNotImplemented return ErrNotImplemented
} }

View File

@ -27,4 +27,5 @@ const (
type InetDiagTCPInfoResp struct { type InetDiagTCPInfoResp struct {
InetDiagMsg *Socket InetDiagMsg *Socket
TCPInfo *TCPInfo TCPInfo *TCPInfo
TCPBBRInfo *TCPBBRInfo
} }

View File

@ -25,11 +25,13 @@ type IPSetEntry struct {
type IPSetResult struct { type IPSetResult struct {
Nfgenmsg *nl.Nfgenmsg Nfgenmsg *nl.Nfgenmsg
Protocol uint8 Protocol uint8
ProtocolMinVersion uint8
Revision uint8 Revision uint8
Family uint8 Family uint8
Flags uint8 Flags uint8
SetName string SetName string
TypeName string TypeName string
Comment string
HashSize uint32 HashSize uint32
NumEntries uint32 NumEntries uint32
@ -38,6 +40,7 @@ type IPSetResult struct {
SizeInMemory uint32 SizeInMemory uint32
CadtFlags uint32 CadtFlags uint32
Timeout *uint32 Timeout *uint32
LineNo uint32
Entries []IPSetEntry Entries []IPSetEntry
} }
@ -52,7 +55,7 @@ type IpsetCreateOptions struct {
} }
// IpsetProtocol returns the ipset protocol version from the kernel // IpsetProtocol returns the ipset protocol version from the kernel
func IpsetProtocol() (uint8, error) { func IpsetProtocol() (uint8, uint8, error) {
return pkgHandle.IpsetProtocol() return pkgHandle.IpsetProtocol()
} }
@ -86,20 +89,20 @@ func IpsetAdd(setname string, entry *IPSetEntry) error {
return pkgHandle.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry) return pkgHandle.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry)
} }
// IpsetDele deletes an entry from an existing ipset. // IpsetDel deletes an entry from an existing ipset.
func IpsetDel(setname string, entry *IPSetEntry) error { func IpsetDel(setname string, entry *IPSetEntry) error {
return pkgHandle.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry) return pkgHandle.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry)
} }
func (h *Handle) IpsetProtocol() (uint8, error) { func (h *Handle) IpsetProtocol() (protocol uint8, minVersion uint8, err error) {
req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL) req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL)
msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0) msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0)
if err != nil { if err != nil {
return 0, err return 0, 0, err
} }
response := ipsetUnserialize(msgs)
return ipsetUnserialize(msgs).Protocol, nil return response.Protocol, response.ProtocolMinVersion, nil
} }
func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error { func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
@ -112,7 +115,7 @@ func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOption
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename)))
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(0))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(0)))
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(0))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(2))) // 2 == inet
data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil) data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
@ -187,6 +190,11 @@ func (h *Handle) IpsetListAll() ([]IPSetResult, error) {
func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error { func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error {
req := h.newIpsetRequest(nlCmd) req := h.newIpsetRequest(nlCmd)
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
if entry.Comment != "" {
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_COMMENT, nl.ZeroTerminated(entry.Comment)))
}
data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil) data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
if !entry.Replace { if !entry.Replace {
@ -197,7 +205,12 @@ func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout}) data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout})
} }
if entry.MAC != nil { if entry.MAC != nil {
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER, entry.MAC)) nestedData := nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NET_BYTEORDER), entry.MAC)
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NESTED), nestedData.Serialize()))
}
if entry.IP != nil {
nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP)
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NESTED), nestedData.Serialize()))
} }
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0}) data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0})
@ -249,6 +262,8 @@ func (result *IPSetResult) unserialize(msg []byte) {
result.Protocol = attr.Value[0] result.Protocol = attr.Value[0]
case nl.IPSET_ATTR_SETNAME: case nl.IPSET_ATTR_SETNAME:
result.SetName = nl.BytesToString(attr.Value) result.SetName = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_COMMENT:
result.Comment = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_TYPENAME: case nl.IPSET_ATTR_TYPENAME:
result.TypeName = nl.BytesToString(attr.Value) result.TypeName = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_REVISION: case nl.IPSET_ATTR_REVISION:
@ -261,6 +276,8 @@ func (result *IPSetResult) unserialize(msg []byte) {
result.parseAttrData(attr.Value) result.parseAttrData(attr.Value)
case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED: case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED:
result.parseAttrADT(attr.Value) result.parseAttrADT(attr.Value)
case nl.IPSET_ATTR_PROTOCOL_MIN:
result.ProtocolMinVersion = attr.Value[0]
default: default:
log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK) log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
} }
@ -285,6 +302,17 @@ func (result *IPSetResult) parseAttrData(data []byte) {
result.SizeInMemory = attr.Uint32() result.SizeInMemory = attr.Uint32()
case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER: case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER:
result.CadtFlags = attr.Uint32() result.CadtFlags = attr.Uint32()
case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
for nested := range nl.ParseAttributes(attr.Value) {
switch nested.Type {
case nl.IPSET_ATTR_IP | nl.NLA_F_NET_BYTEORDER:
result.Entries = append(result.Entries, IPSetEntry{IP: nested.Value})
}
}
case nl.IPSET_ATTR_CADT_LINENO | nl.NLA_F_NET_BYTEORDER:
result.LineNo = attr.Uint32()
case nl.IPSET_ATTR_COMMENT:
result.Comment = nl.BytesToString(attr.Value)
default: default:
log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK) log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
} }
@ -316,6 +344,8 @@ func parseIPSetEntry(data []byte) (entry IPSetEntry) {
entry.Packets = &val entry.Packets = &val
case nl.IPSET_ATTR_ETHER: case nl.IPSET_ATTR_ETHER:
entry.MAC = net.HardwareAddr(attr.Value) entry.MAC = net.HardwareAddr(attr.Value)
case nl.IPSET_ATTR_IP:
entry.IP = net.IP(attr.Value)
case nl.IPSET_ATTR_COMMENT: case nl.IPSET_ATTR_COMMENT:
entry.Comment = nl.BytesToString(attr.Value) entry.Comment = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED: case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:

View File

@ -555,6 +555,27 @@ const (
BOND_ARP_VALIDATE_ALL BOND_ARP_VALIDATE_ALL
) )
var bondArpValidateToString = map[BondArpValidate]string{
BOND_ARP_VALIDATE_NONE: "none",
BOND_ARP_VALIDATE_ACTIVE: "active",
BOND_ARP_VALIDATE_BACKUP: "backup",
BOND_ARP_VALIDATE_ALL: "none",
}
var StringToBondArpValidateMap = map[string]BondArpValidate{
"none": BOND_ARP_VALIDATE_NONE,
"active": BOND_ARP_VALIDATE_ACTIVE,
"backup": BOND_ARP_VALIDATE_BACKUP,
"all": BOND_ARP_VALIDATE_ALL,
}
func (b BondArpValidate) String() string {
s, ok := bondArpValidateToString[b]
if !ok {
return fmt.Sprintf("BondArpValidate(%d)", b)
}
return s
}
// BondPrimaryReselect type // BondPrimaryReselect type
type BondPrimaryReselect int type BondPrimaryReselect int
@ -565,6 +586,25 @@ const (
BOND_PRIMARY_RESELECT_FAILURE BOND_PRIMARY_RESELECT_FAILURE
) )
var bondPrimaryReselectToString = map[BondPrimaryReselect]string{
BOND_PRIMARY_RESELECT_ALWAYS: "always",
BOND_PRIMARY_RESELECT_BETTER: "better",
BOND_PRIMARY_RESELECT_FAILURE: "failure",
}
var StringToBondPrimaryReselectMap = map[string]BondPrimaryReselect{
"always": BOND_PRIMARY_RESELECT_ALWAYS,
"better": BOND_PRIMARY_RESELECT_BETTER,
"failure": BOND_PRIMARY_RESELECT_FAILURE,
}
func (b BondPrimaryReselect) String() string {
s, ok := bondPrimaryReselectToString[b]
if !ok {
return fmt.Sprintf("BondPrimaryReselect(%d)", b)
}
return s
}
// BondArpAllTargets type // BondArpAllTargets type
type BondArpAllTargets int type BondArpAllTargets int
@ -574,6 +614,23 @@ const (
BOND_ARP_ALL_TARGETS_ALL BOND_ARP_ALL_TARGETS_ALL
) )
var bondArpAllTargetsToString = map[BondArpAllTargets]string{
BOND_ARP_ALL_TARGETS_ANY: "any",
BOND_ARP_ALL_TARGETS_ALL: "all",
}
var StringToBondArpAllTargetsMap = map[string]BondArpAllTargets{
"any": BOND_ARP_ALL_TARGETS_ANY,
"all": BOND_ARP_ALL_TARGETS_ALL,
}
func (b BondArpAllTargets) String() string {
s, ok := bondArpAllTargetsToString[b]
if !ok {
return fmt.Sprintf("BondArpAllTargets(%d)", b)
}
return s
}
// BondFailOverMac type // BondFailOverMac type
type BondFailOverMac int type BondFailOverMac int
@ -584,6 +641,25 @@ const (
BOND_FAIL_OVER_MAC_FOLLOW BOND_FAIL_OVER_MAC_FOLLOW
) )
var bondFailOverMacToString = map[BondFailOverMac]string{
BOND_FAIL_OVER_MAC_NONE: "none",
BOND_FAIL_OVER_MAC_ACTIVE: "active",
BOND_FAIL_OVER_MAC_FOLLOW: "follow",
}
var StringToBondFailOverMacMap = map[string]BondFailOverMac{
"none": BOND_FAIL_OVER_MAC_NONE,
"active": BOND_FAIL_OVER_MAC_ACTIVE,
"follow": BOND_FAIL_OVER_MAC_FOLLOW,
}
func (b BondFailOverMac) String() string {
s, ok := bondFailOverMacToString[b]
if !ok {
return fmt.Sprintf("BondFailOverMac(%d)", b)
}
return s
}
// BondXmitHashPolicy type // BondXmitHashPolicy type
type BondXmitHashPolicy int type BondXmitHashPolicy int
@ -675,6 +751,25 @@ const (
BOND_AD_SELECT_COUNT BOND_AD_SELECT_COUNT
) )
var bondAdSelectToString = map[BondAdSelect]string{
BOND_AD_SELECT_STABLE: "stable",
BOND_AD_SELECT_BANDWIDTH: "bandwidth",
BOND_AD_SELECT_COUNT: "count",
}
var StringToBondAdSelectMap = map[string]BondAdSelect{
"stable": BOND_AD_SELECT_STABLE,
"bandwidth": BOND_AD_SELECT_BANDWIDTH,
"count": BOND_AD_SELECT_COUNT,
}
func (b BondAdSelect) String() string {
s, ok := bondAdSelectToString[b]
if !ok {
return fmt.Sprintf("BondAdSelect(%d)", b)
}
return s
}
// BondAdInfo represents ad info for bond // BondAdInfo represents ad info for bond
type BondAdInfo struct { type BondAdInfo struct {
AggregatorId int AggregatorId int
@ -706,7 +801,7 @@ type Bond struct {
AllSlavesActive int AllSlavesActive int
MinLinks int MinLinks int
LpInterval int LpInterval int
PackersPerSlave int PacketsPerSlave int
LacpRate BondLacpRate LacpRate BondLacpRate
AdSelect BondAdSelect AdSelect BondAdSelect
// looking at iproute tool AdInfo can only be retrived. It can't be set. // looking at iproute tool AdInfo can only be retrived. It can't be set.
@ -739,7 +834,7 @@ func NewLinkBond(atr LinkAttrs) *Bond {
AllSlavesActive: -1, AllSlavesActive: -1,
MinLinks: -1, MinLinks: -1,
LpInterval: -1, LpInterval: -1,
PackersPerSlave: -1, PacketsPerSlave: -1,
LacpRate: -1, LacpRate: -1,
AdSelect: -1, AdSelect: -1,
AdActorSysPrio: -1, AdActorSysPrio: -1,
@ -789,8 +884,10 @@ func (bond *Bond) Type() string {
type BondSlaveState uint8 type BondSlaveState uint8
const ( const (
BondStateActive = iota // Link is active. //BondStateActive Link is active.
BondStateBackup // Link is backup. BondStateActive BondSlaveState = iota
//BondStateBackup Link is backup.
BondStateBackup
) )
func (s BondSlaveState) String() string { func (s BondSlaveState) String() string {
@ -804,15 +901,19 @@ func (s BondSlaveState) String() string {
} }
} }
// BondSlaveState represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave // BondSlaveMiiStatus represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave
// attribute, which contains the status of MII link monitoring // attribute, which contains the status of MII link monitoring
type BondSlaveMiiStatus uint8 type BondSlaveMiiStatus uint8
const ( const (
BondLinkUp = iota // link is up and running. //BondLinkUp link is up and running.
BondLinkFail // link has just gone down. BondLinkUp BondSlaveMiiStatus = iota
BondLinkDown // link has been down for too long time. //BondLinkFail link has just gone down.
BondLinkBack // link is going back. BondLinkFail
//BondLinkDown link has been down for too long time.
BondLinkDown
//BondLinkBack link is going back.
BondLinkBack
) )
func (s BondSlaveMiiStatus) String() string { func (s BondSlaveMiiStatus) String() string {
@ -845,6 +946,30 @@ func (b *BondSlave) SlaveType() string {
return "bond" return "bond"
} }
// Geneve devices must specify RemoteIP and ID (VNI) on create
// https://github.com/torvalds/linux/blob/47ec5303d73ea344e84f46660fff693c57641386/drivers/net/geneve.c#L1209-L1223
type Geneve struct {
LinkAttrs
ID uint32 // vni
Remote net.IP
Ttl uint8
Tos uint8
Dport uint16
UdpCsum uint8
UdpZeroCsum6Tx uint8
UdpZeroCsum6Rx uint8
Link uint32
FlowBased bool
}
func (geneve *Geneve) Attrs() *LinkAttrs {
return &geneve.LinkAttrs
}
func (geneve *Geneve) Type() string {
return "geneve"
}
// Gretap devices must specify LocalIP and RemoteIP on create // Gretap devices must specify LocalIP and RemoteIP on create
type Gretap struct { type Gretap struct {
LinkAttrs LinkAttrs
@ -1068,6 +1193,58 @@ var StringToIPoIBMode = map[string]IPoIBMode{
"connected": IPOIB_MODE_CONNECTED, "connected": IPOIB_MODE_CONNECTED,
} }
const (
CAN_STATE_ERROR_ACTIVE = iota
CAN_STATE_ERROR_WARNING
CAN_STATE_ERROR_PASSIVE
CAN_STATE_BUS_OFF
CAN_STATE_STOPPED
CAN_STATE_SLEEPING
)
type Can struct {
LinkAttrs
BitRate uint32
SamplePoint uint32
TimeQuanta uint32
PropagationSegment uint32
PhaseSegment1 uint32
PhaseSegment2 uint32
SyncJumpWidth uint32
BitRatePreScaler uint32
Name string
TimeSegment1Min uint32
TimeSegment1Max uint32
TimeSegment2Min uint32
TimeSegment2Max uint32
SyncJumpWidthMax uint32
BitRatePreScalerMin uint32
BitRatePreScalerMax uint32
BitRatePreScalerInc uint32
ClockFrequency uint32
State uint32
Mask uint32
Flags uint32
TxError uint16
RxError uint16
RestartMs uint32
}
func (can *Can) Attrs() *LinkAttrs {
return &can.LinkAttrs
}
func (can *Can) Type() string {
return "can"
}
type IPoIB struct { type IPoIB struct {
LinkAttrs LinkAttrs
Pkey uint16 Pkey uint16

View File

@ -34,6 +34,21 @@ const (
TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI
) )
var StringToTuntapModeMap = map[string]TuntapMode{
"tun": TUNTAP_MODE_TUN,
"tap": TUNTAP_MODE_TAP,
}
func (ttm TuntapMode) String() string {
switch ttm {
case TUNTAP_MODE_TUN:
return "tun"
case TUNTAP_MODE_TAP:
return "tap"
}
return "unknown"
}
const ( const (
VF_LINK_STATE_AUTO uint32 = 0 VF_LINK_STATE_AUTO uint32 = 0
VF_LINK_STATE_ENABLE uint32 = 1 VF_LINK_STATE_ENABLE uint32 = 1
@ -1046,8 +1061,8 @@ func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) {
if bond.LpInterval >= 0 { if bond.LpInterval >= 0 {
data.AddRtAttr(nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval))) data.AddRtAttr(nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval)))
} }
if bond.PackersPerSlave >= 0 { if bond.PacketsPerSlave >= 0 {
data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PackersPerSlave))) data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PacketsPerSlave)))
} }
if bond.LacpRate >= 0 { if bond.LacpRate >= 0 {
data.AddRtAttr(nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate))) data.AddRtAttr(nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate)))
@ -1404,6 +1419,8 @@ func (h *Handle) linkModify(link Link, flags int) error {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
} }
case *Geneve:
addGeneveAttrs(link, linkInfo)
case *Gretap: case *Gretap:
addGretapAttrs(link, linkInfo) addGretapAttrs(link, linkInfo)
case *Iptun: case *Iptun:
@ -1667,6 +1684,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &Macvlan{} link = &Macvlan{}
case "macvtap": case "macvtap":
link = &Macvtap{} link = &Macvtap{}
case "geneve":
link = &Geneve{}
case "gretap": case "gretap":
link = &Gretap{} link = &Gretap{}
case "ip6gretap": case "ip6gretap":
@ -1693,6 +1712,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &Tuntap{} link = &Tuntap{}
case "ipoib": case "ipoib":
link = &IPoIB{} link = &IPoIB{}
case "can":
link = &Can{}
default: default:
link = &GenericLink{LinkType: linkType} link = &GenericLink{LinkType: linkType}
} }
@ -1714,6 +1735,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
parseMacvlanData(link, data) parseMacvlanData(link, data)
case "macvtap": case "macvtap":
parseMacvtapData(link, data) parseMacvtapData(link, data)
case "geneve":
parseGeneveData(link, data)
case "gretap": case "gretap":
parseGretapData(link, data) parseGretapData(link, data)
case "ip6gretap": case "ip6gretap":
@ -1742,6 +1765,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
parseTuntapData(link, data) parseTuntapData(link, data)
case "ipoib": case "ipoib":
parseIPoIBData(link, data) parseIPoIBData(link, data)
case "can":
parseCanData(link, data)
} }
case nl.IFLA_INFO_SLAVE_KIND: case nl.IFLA_INFO_SLAVE_KIND:
slaveType = string(info.Value[:len(info.Value)-1]) slaveType = string(info.Value[:len(info.Value)-1])
@ -2299,7 +2324,7 @@ func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_BOND_LP_INTERVAL: case nl.IFLA_BOND_LP_INTERVAL:
bond.LpInterval = int(native.Uint32(data[i].Value[0:4])) bond.LpInterval = int(native.Uint32(data[i].Value[0:4]))
case nl.IFLA_BOND_PACKETS_PER_SLAVE: case nl.IFLA_BOND_PACKETS_PER_SLAVE:
bond.PackersPerSlave = int(native.Uint32(data[i].Value[0:4])) bond.PacketsPerSlave = int(native.Uint32(data[i].Value[0:4]))
case nl.IFLA_BOND_AD_LACP_RATE: case nl.IFLA_BOND_AD_LACP_RATE:
bond.LacpRate = BondLacpRate(data[i].Value[0]) bond.LacpRate = BondLacpRate(data[i].Value[0])
case nl.IFLA_BOND_AD_SELECT: case nl.IFLA_BOND_AD_SELECT:
@ -2448,6 +2473,58 @@ func linkFlags(rawFlags uint32) net.Flags {
return f return f
} }
func addGeneveAttrs(geneve *Geneve, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
if geneve.FlowBased {
// In flow based mode, no other attributes need to be configured
linkInfo.AddRtAttr(nl.IFLA_GENEVE_COLLECT_METADATA, boolAttr(geneve.FlowBased))
return
}
if ip := geneve.Remote; ip != nil {
if ip4 := ip.To4(); ip4 != nil {
data.AddRtAttr(nl.IFLA_GENEVE_REMOTE, ip.To4())
} else {
data.AddRtAttr(nl.IFLA_GENEVE_REMOTE6, []byte(ip))
}
}
if geneve.ID != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_ID, nl.Uint32Attr(geneve.ID))
}
if geneve.Dport != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_PORT, htons(geneve.Dport))
}
if geneve.Ttl != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_TTL, nl.Uint8Attr(geneve.Ttl))
}
if geneve.Tos != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_TOS, nl.Uint8Attr(geneve.Tos))
}
}
func parseGeneveData(link Link, data []syscall.NetlinkRouteAttr) {
geneve := link.(*Geneve)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_GENEVE_ID:
geneve.ID = native.Uint32(datum.Value[0:4])
case nl.IFLA_GENEVE_REMOTE, nl.IFLA_GENEVE_REMOTE6:
geneve.Remote = datum.Value
case nl.IFLA_GENEVE_PORT:
geneve.Dport = ntohs(datum.Value[0:2])
case nl.IFLA_GENEVE_TTL:
geneve.Ttl = uint8(datum.Value[0])
case nl.IFLA_GENEVE_TOS:
geneve.Tos = uint8(datum.Value[0])
}
}
}
func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) { func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
@ -3172,6 +3249,54 @@ func parseIPoIBData(link Link, data []syscall.NetlinkRouteAttr) {
} }
} }
func parseCanData(link Link, data []syscall.NetlinkRouteAttr) {
can := link.(*Can)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_CAN_BITTIMING:
can.BitRate = native.Uint32(datum.Value)
can.SamplePoint = native.Uint32(datum.Value[4:])
can.TimeQuanta = native.Uint32(datum.Value[8:])
can.PropagationSegment = native.Uint32(datum.Value[12:])
can.PhaseSegment1 = native.Uint32(datum.Value[16:])
can.PhaseSegment2 = native.Uint32(datum.Value[20:])
can.SyncJumpWidth = native.Uint32(datum.Value[24:])
can.BitRatePreScaler = native.Uint32(datum.Value[28:])
case nl.IFLA_CAN_BITTIMING_CONST:
can.Name = string(datum.Value[:16])
can.TimeSegment1Min = native.Uint32(datum.Value[16:])
can.TimeSegment1Max = native.Uint32(datum.Value[20:])
can.TimeSegment2Min = native.Uint32(datum.Value[24:])
can.TimeSegment2Max = native.Uint32(datum.Value[28:])
can.SyncJumpWidthMax = native.Uint32(datum.Value[32:])
can.BitRatePreScalerMin = native.Uint32(datum.Value[36:])
can.BitRatePreScalerMax = native.Uint32(datum.Value[40:])
can.BitRatePreScalerInc = native.Uint32(datum.Value[44:])
case nl.IFLA_CAN_CLOCK:
can.ClockFrequency = native.Uint32(datum.Value)
case nl.IFLA_CAN_STATE:
can.State = native.Uint32(datum.Value)
case nl.IFLA_CAN_CTRLMODE:
can.Mask = native.Uint32(datum.Value)
can.Flags = native.Uint32(datum.Value[4:])
case nl.IFLA_CAN_BERR_COUNTER:
can.TxError = native.Uint16(datum.Value)
can.RxError = native.Uint16(datum.Value[2:])
case nl.IFLA_CAN_RESTART_MS:
can.RestartMs = native.Uint32(datum.Value)
case nl.IFLA_CAN_DATA_BITTIMING_CONST:
case nl.IFLA_CAN_RESTART:
case nl.IFLA_CAN_DATA_BITTIMING:
case nl.IFLA_CAN_TERMINATION:
case nl.IFLA_CAN_TERMINATION_CONST:
case nl.IFLA_CAN_BITRATE_CONST:
case nl.IFLA_CAN_DATA_BITRATE_CONST:
case nl.IFLA_CAN_BITRATE_MAX:
}
}
}
func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) { func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_IPOIB_PKEY, nl.Uint16Attr(uint16(ipoib.Pkey))) data.AddRtAttr(nl.IFLA_IPOIB_PKEY, nl.Uint16Attr(uint16(ipoib.Pkey)))

View File

@ -10,6 +10,7 @@ const (
const ( const (
DEVLINK_CMD_GET = 1 DEVLINK_CMD_GET = 1
DEVLINK_CMD_PORT_GET = 5
DEVLINK_CMD_ESWITCH_GET = 29 DEVLINK_CMD_ESWITCH_GET = 29
DEVLINK_CMD_ESWITCH_SET = 30 DEVLINK_CMD_ESWITCH_SET = 30
) )
@ -17,9 +18,15 @@ const (
const ( const (
DEVLINK_ATTR_BUS_NAME = 1 DEVLINK_ATTR_BUS_NAME = 1
DEVLINK_ATTR_DEV_NAME = 2 DEVLINK_ATTR_DEV_NAME = 2
DEVLINK_ATTR_PORT_INDEX = 3
DEVLINK_ATTR_PORT_TYPE = 4
DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
DEVLINK_ATTR_ESWITCH_MODE = 25 DEVLINK_ATTR_ESWITCH_MODE = 25
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26 DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62 DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
DEVLINK_ATTR_PORT_FLAVOUR = 77
) )
const ( const (
@ -38,3 +45,19 @@ const (
DEVLINK_ESWITCH_ENCAP_MODE_NONE = 0 DEVLINK_ESWITCH_ENCAP_MODE_NONE = 0
DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1 DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1
) )
const (
DEVLINK_PORT_FLAVOUR_PHYSICAL = 0
DEVLINK_PORT_FLAVOUR_CPU = 1
DEVLINK_PORT_FLAVOUR_DSA = 2
DEVLINK_PORT_FLAVOUR_PCI_PF = 3
DEVLINK_PORT_FLAVOUR_PCI_VF = 4
DEVLINK_PORT_FLAVOUR_VIRTUAL = 5
)
const (
DEVLINK_PORT_TYPE_NOTSET = 0
DEVLINK_PORT_TYPE_AUTO = 1
DEVLINK_PORT_TYPE_ETH = 2
DEVLINK_PORT_TYPE_IB = 3
)

View File

@ -173,6 +173,22 @@ const (
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE
) )
const (
IFLA_GENEVE_UNSPEC = iota
IFLA_GENEVE_ID // vni
IFLA_GENEVE_REMOTE
IFLA_GENEVE_TTL
IFLA_GENEVE_TOS
IFLA_GENEVE_PORT // destination port
IFLA_GENEVE_COLLECT_METADATA
IFLA_GENEVE_REMOTE6
IFLA_GENEVE_UDP_CSUM
IFLA_GENEVE_UDP_ZERO_CSUM6_TX
IFLA_GENEVE_UDP_ZERO_CSUM6_RX
IFLA_GENEVE_LABEL
IFLA_GENEVE_MAX = IFLA_GENEVE_LABEL
)
const ( const (
IFLA_GRE_UNSPEC = iota IFLA_GRE_UNSPEC = iota
IFLA_GRE_LINK IFLA_GRE_LINK
@ -673,3 +689,23 @@ const (
IFLA_IPOIB_UMCAST IFLA_IPOIB_UMCAST
IFLA_IPOIB_MAX = IFLA_IPOIB_UMCAST IFLA_IPOIB_MAX = IFLA_IPOIB_UMCAST
) )
const (
IFLA_CAN_UNSPEC = iota
IFLA_CAN_BITTIMING
IFLA_CAN_BITTIMING_CONST
IFLA_CAN_CLOCK
IFLA_CAN_STATE
IFLA_CAN_CTRLMODE
IFLA_CAN_RESTART_MS
IFLA_CAN_RESTART
IFLA_CAN_BERR_COUNTER
IFLA_CAN_DATA_BITTIMING
IFLA_CAN_DATA_BITTIMING_CONST
IFLA_CAN_TERMINATION
IFLA_CAN_TERMINATION_CONST
IFLA_CAN_BITRATE_CONST
IFLA_CAN_DATA_BITRATE_CONST
IFLA_CAN_BITRATE_MAX
IFLA_CAN_MAX = IFLA_CAN_BITRATE_MAX
)

View File

@ -35,6 +35,9 @@ var SupportedNlFamilies = []int{unix.NETLINK_ROUTE, unix.NETLINK_XFRM, unix.NETL
var nextSeqNr uint32 var nextSeqNr uint32
// Default netlink socket timeout, 60s
var SocketTimeoutTv = unix.Timeval{Sec: 60, Usec: 0}
// GetIPFamily returns the family type of a net.IP. // GetIPFamily returns the family type of a net.IP.
func GetIPFamily(ip net.IP) int { func GetIPFamily(ip net.IP) int {
if len(ip) <= net.IPv4len { if len(ip) <= net.IPv4len {
@ -426,6 +429,14 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := s.SetSendTimeout(&SocketTimeoutTv); err != nil {
return nil, err
}
if err := s.SetReceiveTimeout(&SocketTimeoutTv); err != nil {
return nil, err
}
defer s.Close() defer s.Close()
} else { } else {
s.Lock() s.Lock()

View File

@ -3,6 +3,7 @@ package nl
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"log"
) )
type Attribute struct { type Attribute struct {
@ -18,9 +19,20 @@ func ParseAttributes(data []byte) <-chan Attribute {
i := 0 i := 0
for i+4 < len(data) { for i+4 < len(data) {
length := int(native.Uint16(data[i : i+2])) length := int(native.Uint16(data[i : i+2]))
attrType := native.Uint16(data[i+2 : i+4])
if length < 4 {
log.Printf("attribute 0x%02x has invalid length of %d bytes", attrType, length)
break
}
if len(data) < i+length {
log.Printf("attribute 0x%02x of length %d is truncated, only %d bytes remaining", attrType, length, len(data)-i)
break
}
result <- Attribute{ result <- Attribute{
Type: native.Uint16(data[i+2 : i+4]), Type: attrType,
Value: data[i+4 : i+length], Value: data[i+4 : i+length],
} }
i += rtaAlignOf(length) i += rtaAlignOf(length)

View File

@ -314,7 +314,9 @@ type FqCodel struct {
ECN uint32 ECN uint32
Flows uint32 Flows uint32
Quantum uint32 Quantum uint32
// There are some more attributes here, but support for them seems not ubiquitous CEThreshold uint32
DropBatchSize uint32
MemoryLimit uint32
} }
func (fqcodel *FqCodel) String() string { func (fqcodel *FqCodel) String() string {

View File

@ -250,7 +250,15 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
if qdisc.Quantum > 0 { if qdisc.Quantum > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum)))) options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
} }
if qdisc.CEThreshold > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_CE_THRESHOLD, nl.Uint32Attr(qdisc.CEThreshold))
}
if qdisc.DropBatchSize > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_DROP_BATCH_SIZE, nl.Uint32Attr(qdisc.DropBatchSize))
}
if qdisc.MemoryLimit > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_MEMORY_LIMIT, nl.Uint32Attr(qdisc.MemoryLimit))
}
case *Fq: case *Fq:
options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing)))) options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
@ -497,6 +505,12 @@ func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
fqCodel.Flows = native.Uint32(datum.Value) fqCodel.Flows = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_QUANTUM: case nl.TCA_FQ_CODEL_QUANTUM:
fqCodel.Quantum = native.Uint32(datum.Value) fqCodel.Quantum = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_CE_THRESHOLD:
fqCodel.CEThreshold = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_DROP_BATCH_SIZE:
fqCodel.DropBatchSize = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_MEMORY_LIMIT:
fqCodel.MemoryLimit = native.Uint32(datum.Value)
} }
} }
return nil return nil

View File

@ -27,6 +27,9 @@ type Encap interface {
Equal(Encap) bool Equal(Encap) bool
} }
//Protocol describe what was the originator of the route
type RouteProtocol int
// Route represents a netlink route. // Route represents a netlink route.
type Route struct { type Route struct {
LinkIndex int LinkIndex int
@ -36,7 +39,7 @@ type Route struct {
Src net.IP Src net.IP
Gw net.IP Gw net.IP
MultiPath []*NexthopInfo MultiPath []*NexthopInfo
Protocol int Protocol RouteProtocol
Priority int Priority int
Table int Table int
Type int Type int
@ -45,6 +48,7 @@ type Route struct {
MPLSDst *int MPLSDst *int
NewDst Destination NewDst Destination
Encap Encap Encap Encap
Via Destination
MTU int MTU int
Window int Window int
Rtt int Rtt int
@ -79,6 +83,9 @@ func (r Route) String() string {
if r.Encap != nil { if r.Encap != nil {
elems = append(elems, fmt.Sprintf("Encap: %s", r.Encap)) elems = append(elems, fmt.Sprintf("Encap: %s", r.Encap))
} }
if r.Via != nil {
elems = append(elems, fmt.Sprintf("Via: %s", r.Via))
}
elems = append(elems, fmt.Sprintf("Src: %s", r.Src)) elems = append(elems, fmt.Sprintf("Src: %s", r.Src))
if len(r.MultiPath) > 0 { if len(r.MultiPath) > 0 {
elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath)) elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath))
@ -107,6 +114,7 @@ func (r Route) Equal(x Route) bool {
r.Flags == x.Flags && r.Flags == x.Flags &&
(r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) && (r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) &&
(r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) && (r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) &&
(r.Via == x.Via || (r.Via != nil && r.Via.Equal(x.Via))) &&
(r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap))) (r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap)))
} }
@ -136,6 +144,7 @@ type NexthopInfo struct {
Flags int Flags int
NewDst Destination NewDst Destination
Encap Encap Encap Encap
Via Destination
} }
func (n *NexthopInfo) String() string { func (n *NexthopInfo) String() string {
@ -147,6 +156,9 @@ func (n *NexthopInfo) String() string {
if n.Encap != nil { if n.Encap != nil {
elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap)) elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap))
} }
if n.Via != nil {
elems = append(elems, fmt.Sprintf("Via: %s", n.Via))
}
elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1)) elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1))
elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw)) elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw))
elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags())) elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags()))

View File

@ -1,8 +1,11 @@
package netlink package netlink
import ( import (
"bytes"
"encoding/binary"
"fmt" "fmt"
"net" "net"
"strconv"
"strings" "strings"
"syscall" "syscall"
@ -21,6 +24,23 @@ const (
SCOPE_NOWHERE Scope = unix.RT_SCOPE_NOWHERE SCOPE_NOWHERE Scope = unix.RT_SCOPE_NOWHERE
) )
func (s Scope) String() string {
switch s {
case SCOPE_UNIVERSE:
return "universe"
case SCOPE_SITE:
return "site"
case SCOPE_LINK:
return "link"
case SCOPE_HOST:
return "host"
case SCOPE_NOWHERE:
return "nowhere"
default:
return "unknown"
}
}
const ( const (
RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota) RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota)
RT_FILTER_SCOPE RT_FILTER_SCOPE
@ -446,6 +466,62 @@ func (e *SEG6LocalEncap) Equal(x Encap) bool {
return true return true
} }
type Via struct {
AddrFamily int
Addr net.IP
}
func (v *Via) Equal(x Destination) bool {
o, ok := x.(*Via)
if !ok {
return false
}
if v.AddrFamily == x.Family() && v.Addr.Equal(o.Addr) {
return true
}
return false
}
func (v *Via) String() string {
return fmt.Sprintf("Family: %d, Address: %s", v.AddrFamily, v.Addr.String())
}
func (v *Via) Family() int {
return v.AddrFamily
}
func (v *Via) Encode() ([]byte, error) {
buf := &bytes.Buffer{}
err := binary.Write(buf, native, uint16(v.AddrFamily))
if err != nil {
return nil, err
}
err = binary.Write(buf, native, v.Addr)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (v *Via) Decode(b []byte) error {
native := nl.NativeEndian()
if len(b) < 6 {
return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b))
}
v.AddrFamily = int(native.Uint16(b[0:2]))
if v.AddrFamily == nl.FAMILY_V4 {
v.Addr = net.IP(b[2:6])
return nil
} else if v.AddrFamily == nl.FAMILY_V6 {
if len(b) < 18 {
return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b))
}
v.Addr = net.IP(b[2:])
return nil
}
return fmt.Errorf("decoding failed: address family %d unknown", v.AddrFamily)
}
// RouteAdd will add a route to the system. // RouteAdd will add a route to the system.
// Equivalent to: `ip route add $route` // Equivalent to: `ip route add $route`
func RouteAdd(route *Route) error { func RouteAdd(route *Route) error {
@ -460,6 +536,32 @@ func (h *Handle) RouteAdd(route *Route) error {
return h.routeHandle(route, req, nl.NewRtMsg()) return h.routeHandle(route, req, nl.NewRtMsg())
} }
// RouteAppend will append a route to the system.
// Equivalent to: `ip route append $route`
func RouteAppend(route *Route) error {
return pkgHandle.RouteAppend(route)
}
// RouteAppend will append a route to the system.
// Equivalent to: `ip route append $route`
func (h *Handle) RouteAppend(route *Route) error {
flags := unix.NLM_F_CREATE | unix.NLM_F_APPEND | unix.NLM_F_ACK
req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
}
// RouteAddEcmp will add a route to the system.
func RouteAddEcmp(route *Route) error {
return pkgHandle.RouteAddEcmp(route)
}
// RouteAddEcmp will add a route to the system.
func (h *Handle) RouteAddEcmp(route *Route) error {
flags := unix.NLM_F_CREATE | unix.NLM_F_ACK
req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
}
// RouteReplace will add a route to the system. // RouteReplace will add a route to the system.
// Equivalent to: `ip route replace $route` // Equivalent to: `ip route replace $route`
func RouteReplace(route *Route) error { func RouteReplace(route *Route) error {
@ -567,6 +669,14 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData))
} }
if route.Via != nil {
buf, err := route.Via.Encode()
if err != nil {
return fmt.Errorf("failed to encode RTA_VIA: %v", err)
}
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_VIA, buf))
}
if len(route.MultiPath) > 0 { if len(route.MultiPath) > 0 {
buf := []byte{} buf := []byte{}
for _, nh := range route.MultiPath { for _, nh := range route.MultiPath {
@ -609,6 +719,13 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
} }
children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf)) children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf))
} }
if nh.Via != nil {
buf, err := nh.Via.Encode()
if err != nil {
return err
}
children = append(children, nl.NewRtAttr(unix.RTA_VIA, buf))
}
rtnh.Children = children rtnh.Children = children
buf = append(buf, rtnh.Serialize()...) buf = append(buf, rtnh.Serialize()...)
} }
@ -834,7 +951,7 @@ func deserializeRoute(m []byte) (Route, error) {
} }
route := Route{ route := Route{
Scope: Scope(msg.Scope), Scope: Scope(msg.Scope),
Protocol: int(msg.Protocol), Protocol: RouteProtocol(int(msg.Protocol)),
Table: int(msg.Table), Table: int(msg.Table),
Type: int(msg.Type), Type: int(msg.Type),
Tos: int(msg.Tos), Tos: int(msg.Tos),
@ -907,6 +1024,12 @@ func deserializeRoute(m []byte) (Route, error) {
encapType = attr encapType = attr
case unix.RTA_ENCAP: case unix.RTA_ENCAP:
encap = attr encap = attr
case unix.RTA_VIA:
d := &Via{}
if err := d.Decode(attr.Value); err != nil {
return nil, nil, err
}
info.Via = d
} }
} }
@ -944,6 +1067,12 @@ func deserializeRoute(m []byte) (Route, error) {
return route, err return route, err
} }
route.NewDst = d route.NewDst = d
case unix.RTA_VIA:
v := &Via{}
if err := v.Decode(attr.Value); err != nil {
return route, err
}
route.Via = v
case unix.RTA_ENCAP_TYPE: case unix.RTA_ENCAP_TYPE:
encapType = attr encapType = attr
case unix.RTA_ENCAP: case unix.RTA_ENCAP:
@ -1022,6 +1151,7 @@ func deserializeRoute(m []byte) (Route, error) {
// RouteGetWithOptions // RouteGetWithOptions
type RouteGetOptions struct { type RouteGetOptions struct {
VrfName string VrfName string
SrcAddr net.IP
} }
// RouteGetWithOptions gets a route to a specific destination from the host system. // RouteGetWithOptions gets a route to a specific destination from the host system.
@ -1053,12 +1183,17 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption
msg := &nl.RtMsg{} msg := &nl.RtMsg{}
msg.Family = uint8(family) msg.Family = uint8(family)
msg.Dst_len = bitlen msg.Dst_len = bitlen
if options != nil && options.SrcAddr != nil {
msg.Src_len = bitlen
}
msg.Flags = unix.RTM_F_LOOKUP_TABLE
req.AddData(msg) req.AddData(msg)
rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData) rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData)
req.AddData(rtaDst) req.AddData(rtaDst)
if options != nil { if options != nil {
if options.VrfName != "" {
link, err := LinkByName(options.VrfName) link, err := LinkByName(options.VrfName)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1072,6 +1207,18 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b)) req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
} }
if options.SrcAddr != nil {
var srcAddr []byte
if family == FAMILY_V4 {
srcAddr = options.SrcAddr.To4()
} else {
srcAddr = options.SrcAddr.To16()
}
req.AddData(nl.NewRtAttr(unix.RTA_SRC, srcAddr))
}
}
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1190,3 +1337,54 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
return nil return nil
} }
func (p RouteProtocol) String() string {
switch int(p) {
case unix.RTPROT_BABEL:
return "babel"
case unix.RTPROT_BGP:
return "bgp"
case unix.RTPROT_BIRD:
return "bird"
case unix.RTPROT_BOOT:
return "boot"
case unix.RTPROT_DHCP:
return "dhcp"
case unix.RTPROT_DNROUTED:
return "dnrouted"
case unix.RTPROT_EIGRP:
return "eigrp"
case unix.RTPROT_GATED:
return "gated"
case unix.RTPROT_ISIS:
return "isis"
//case unix.RTPROT_KEEPALIVED:
// return "keepalived"
case unix.RTPROT_KERNEL:
return "kernel"
case unix.RTPROT_MROUTED:
return "mrouted"
case unix.RTPROT_MRT:
return "mrt"
case unix.RTPROT_NTK:
return "ntk"
case unix.RTPROT_OSPF:
return "ospf"
case unix.RTPROT_RA:
return "ra"
case unix.RTPROT_REDIRECT:
return "redirect"
case unix.RTPROT_RIP:
return "rip"
case unix.RTPROT_STATIC:
return "static"
case unix.RTPROT_UNSPEC:
return "unspec"
case unix.RTPROT_XORP:
return "xorp"
case unix.RTPROT_ZEBRA:
return "zebra"
default:
return strconv.Itoa(int(p))
}
}

View File

@ -2,6 +2,8 @@
package netlink package netlink
import "strconv"
func (r *Route) ListFlags() []string { func (r *Route) ListFlags() []string {
return []string{} return []string{}
} }
@ -9,3 +11,11 @@ func (r *Route) ListFlags() []string {
func (n *NexthopInfo) ListFlags() []string { func (n *NexthopInfo) ListFlags() []string {
return []string{} return []string{}
} }
func (s Scope) String() string {
return "unknown"
}
func (p RouteProtocol) String() string {
return strconv.Itoa(int(p))
}

View File

@ -184,7 +184,7 @@ func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
req.AddData(&socketRequest{ req.AddData(&socketRequest{
Family: family, Family: family,
Protocol: unix.IPPROTO_TCP, Protocol: unix.IPPROTO_TCP,
Ext: INET_DIAG_INFO, Ext: (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)),
States: uint32(0xfff), // All TCP states States: uint32(0xfff), // All TCP states
}) })
s.Send(req) s.Send(req)
@ -220,19 +220,42 @@ loop:
if err != nil { if err != nil {
return nil, err return nil, err
} }
res, err := attrsToInetDiagTCPInfoResp(attrs, sockInfo)
if err != nil {
return nil, err
}
result = append(result, res)
}
}
return result, nil
}
func attrsToInetDiagTCPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagTCPInfoResp, error) {
var tcpInfo *TCPInfo var tcpInfo *TCPInfo
var tcpBBRInfo *TCPBBRInfo
for _, a := range attrs { for _, a := range attrs {
if a.Attr.Type == INET_DIAG_INFO { if a.Attr.Type == INET_DIAG_INFO {
tcpInfo = &TCPInfo{} tcpInfo = &TCPInfo{}
if err := tcpInfo.deserialize(a.Value); err != nil { if err := tcpInfo.deserialize(a.Value); err != nil {
return nil, err return nil, err
} }
break continue
}
if a.Attr.Type == INET_DIAG_BBRINFO {
tcpBBRInfo = &TCPBBRInfo{}
if err := tcpBBRInfo.deserialize(a.Value); err != nil {
return nil, err
}
continue
} }
} }
r := &InetDiagTCPInfoResp{InetDiagMsg: sockInfo, TCPInfo: tcpInfo}
result = append(result, r) return &InetDiagTCPInfoResp{
} InetDiagMsg: sockInfo,
} TCPInfo: tcpInfo,
return result, nil TCPBBRInfo: tcpBBRInfo,
}, nil
} }

View File

@ -16,3 +16,69 @@ const (
TCP_NEW_SYN_REC TCP_NEW_SYN_REC
TCP_MAX_STATES TCP_MAX_STATES
) )
type TCPInfo struct {
State uint8
Ca_state uint8
Retransmits uint8
Probes uint8
Backoff uint8
Options uint8
Snd_wscale uint8 // no uint4
Rcv_wscale uint8
Delivery_rate_app_limited uint8
Fastopen_client_fail uint8
Rto uint32
Ato uint32
Snd_mss uint32
Rcv_mss uint32
Unacked uint32
Sacked uint32
Lost uint32
Retrans uint32
Fackets uint32
Last_data_sent uint32
Last_ack_sent uint32
Last_data_recv uint32
Last_ack_recv uint32
Pmtu uint32
Rcv_ssthresh uint32
Rtt uint32
Rttvar uint32
Snd_ssthresh uint32
Snd_cwnd uint32
Advmss uint32
Reordering uint32
Rcv_rtt uint32
Rcv_space uint32
Total_retrans uint32
Pacing_rate uint64
Max_pacing_rate uint64
Bytes_acked uint64 /* RFC4898 tcpEStatsAppHCThruOctetsAcked */
Bytes_received uint64 /* RFC4898 tcpEStatsAppHCThruOctetsReceived */
Segs_out uint32 /* RFC4898 tcpEStatsPerfSegsOut */
Segs_in uint32 /* RFC4898 tcpEStatsPerfSegsIn */
Notsent_bytes uint32
Min_rtt uint32
Data_segs_in uint32 /* RFC4898 tcpEStatsDataSegsIn */
Data_segs_out uint32 /* RFC4898 tcpEStatsDataSegsOut */
Delivery_rate uint64
Busy_time uint64 /* Time (usec) busy sending data */
Rwnd_limited uint64 /* Time (usec) limited by receive window */
Sndbuf_limited uint64 /* Time (usec) limited by send buffer */
Delivered uint32
Delivered_ce uint32
Bytes_sent uint64 /* RFC4898 tcpEStatsPerfHCDataOctetsOut */
Bytes_retrans uint64 /* RFC4898 tcpEStatsPerfOctetsRetrans */
Dsack_dups uint32 /* RFC4898 tcpEStatsStackDSACKDups */
Reord_seen uint32 /* reordering events seen */
Rcv_ooopack uint32 /* Out-of-order packets received */
Snd_wnd uint32 /* peer's advertised receive window after * scaling (bytes) */
}
type TCPBBRInfo struct {
BBRBW uint64
BBRMinRTT uint32
BBRPacingGain uint32
BBRCwndGain uint32
}

View File

@ -2,67 +2,13 @@ package netlink
import ( import (
"bytes" "bytes"
"errors"
"io" "io"
) )
type TCPInfo struct { const (
State uint8 tcpBBRInfoLen = 20
Ca_state uint8 )
Retransmits uint8
Probes uint8
Backoff uint8
Options uint8
Snd_wscale uint8 // no uint4
Rcv_wscale uint8
Delivery_rate_app_limited uint8
Fastopen_client_fail uint8
Rto uint32
Ato uint32
Snd_mss uint32
Rcv_mss uint32
Unacked uint32
Sacked uint32
Lost uint32
Retrans uint32
Fackets uint32
Last_data_sent uint32
Last_ack_sent uint32
Last_data_recv uint32
Last_ack_recv uint32
Pmtu uint32
Rcv_ssthresh uint32
Rtt uint32
Rttvar uint32
Snd_ssthresh uint32
Snd_cwnd uint32
Advmss uint32
Reordering uint32
Rcv_rtt uint32
Rcv_space uint32
Total_retrans uint32
Pacing_rate uint64
Max_pacing_rate uint64
Bytes_acked uint64 /* RFC4898 tcpEStatsAppHCThruOctetsAcked */
Bytes_received uint64 /* RFC4898 tcpEStatsAppHCThruOctetsReceived */
Segs_out uint32 /* RFC4898 tcpEStatsPerfSegsOut */
Segs_in uint32 /* RFC4898 tcpEStatsPerfSegsIn */
Notsent_bytes uint32
Min_rtt uint32
Data_segs_in uint32 /* RFC4898 tcpEStatsDataSegsIn */
Data_segs_out uint32 /* RFC4898 tcpEStatsDataSegsOut */
Delivery_rate uint64
Busy_time uint64 /* Time (usec) busy sending data */
Rwnd_limited uint64 /* Time (usec) limited by receive window */
Sndbuf_limited uint64 /* Time (usec) limited by send buffer */
Delivered uint32
Delivered_ce uint32
Bytes_sent uint64 /* RFC4898 tcpEStatsPerfHCDataOctetsOut */
Bytes_retrans uint64 /* RFC4898 tcpEStatsPerfOctetsRetrans */
Dsack_dups uint32 /* RFC4898 tcpEStatsStackDSACKDups */
Reord_seen uint32 /* reordering events seen */
Rcv_ooopack uint32 /* Out-of-order packets received */
Snd_wnd uint32 /* peer's advertised receive window after * scaling (bytes) */
}
func checkDeserErr(err error) error { func checkDeserErr(err error) error {
if err == io.EOF { if err == io.EOF {
@ -391,3 +337,17 @@ func (t *TCPInfo) deserialize(b []byte) error {
t.Snd_wnd = native.Uint32(next) t.Snd_wnd = native.Uint32(next)
return nil return nil
} }
func (t *TCPBBRInfo) deserialize(b []byte) error {
if len(b) != tcpBBRInfoLen {
return errors.New("Invalid length")
}
rb := bytes.NewBuffer(b)
t.BBRBW = native.Uint64(rb.Next(8))
t.BBRMinRTT = native.Uint32(rb.Next(4))
t.BBRPacingGain = native.Uint32(rb.Next(4))
t.BBRCwndGain = native.Uint32(rb.Next(4))
return nil
}

View File

@ -64,6 +64,7 @@ type XfrmPolicyTmpl struct {
Mode Mode Mode Mode
Spi int Spi int
Reqid int Reqid int
Optional int
} }
func (t XfrmPolicyTmpl) String() string { func (t XfrmPolicyTmpl) String() string {

View File

@ -79,6 +79,7 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
userTmpl.XfrmId.Spi = nl.Swap32(uint32(tmpl.Spi)) userTmpl.XfrmId.Spi = nl.Swap32(uint32(tmpl.Spi))
userTmpl.Mode = uint8(tmpl.Mode) userTmpl.Mode = uint8(tmpl.Mode)
userTmpl.Reqid = uint32(tmpl.Reqid) userTmpl.Reqid = uint32(tmpl.Reqid)
userTmpl.Optional = uint8(tmpl.Optional)
userTmpl.Aalgos = ^uint32(0) userTmpl.Aalgos = ^uint32(0)
userTmpl.Ealgos = ^uint32(0) userTmpl.Ealgos = ^uint32(0)
userTmpl.Calgos = ^uint32(0) userTmpl.Calgos = ^uint32(0)
@ -247,6 +248,7 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
resTmpl.Mode = Mode(tmpl.Mode) resTmpl.Mode = Mode(tmpl.Mode)
resTmpl.Spi = int(nl.Swap32(tmpl.XfrmId.Spi)) resTmpl.Spi = int(nl.Swap32(tmpl.XfrmId.Spi))
resTmpl.Reqid = int(tmpl.Reqid) resTmpl.Reqid = int(tmpl.Reqid)
resTmpl.Optional = int(tmpl.Optional)
policy.Tmpls = append(policy.Tmpls, resTmpl) policy.Tmpls = append(policy.Tmpls, resTmpl)
} }
case nl.XFRMA_MARK: case nl.XFRMA_MARK:

View File

@ -94,7 +94,7 @@ type XfrmState struct {
Limits XfrmStateLimits Limits XfrmStateLimits
Statistics XfrmStateStats Statistics XfrmStateStats
Mark *XfrmMark Mark *XfrmMark
OutputMark int OutputMark *XfrmMark
Ifid int Ifid int
Auth *XfrmStateAlgo Auth *XfrmStateAlgo
Crypt *XfrmStateAlgo Crypt *XfrmStateAlgo
@ -104,7 +104,7 @@ type XfrmState struct {
} }
func (sa XfrmState) String() string { func (sa XfrmState) String() string {
return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, OutputMark: %d, Ifid: %d, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t", return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, OutputMark: %v, Ifid: %d, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t",
sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.OutputMark, sa.Ifid, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN) sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.OutputMark, sa.Ifid, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN)
} }
func (sa XfrmState) Print(stats bool) string { func (sa XfrmState) Print(stats bool) string {

View File

@ -158,9 +158,13 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow)) out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow))
req.AddData(out) req.AddData(out)
} }
if state.OutputMark != 0 { if state.OutputMark != nil {
out := nl.NewRtAttr(nl.XFRMA_OUTPUT_MARK, nl.Uint32Attr(uint32(state.OutputMark))) out := nl.NewRtAttr(nl.XFRMA_SET_MARK, nl.Uint32Attr(state.OutputMark.Value))
req.AddData(out) req.AddData(out)
if state.OutputMark.Mask != 0 {
out = nl.NewRtAttr(nl.XFRMA_SET_MARK_MASK, nl.Uint32Attr(state.OutputMark.Mask))
req.AddData(out)
}
} }
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid))) ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
@ -377,8 +381,19 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
state.Mark = new(XfrmMark) state.Mark = new(XfrmMark)
state.Mark.Value = mark.Value state.Mark.Value = mark.Value
state.Mark.Mask = mark.Mask state.Mark.Mask = mark.Mask
case nl.XFRMA_OUTPUT_MARK: case nl.XFRMA_SET_MARK:
state.OutputMark = int(native.Uint32(attr.Value)) if state.OutputMark == nil {
state.OutputMark = new(XfrmMark)
}
state.OutputMark.Value = native.Uint32(attr.Value)
case nl.XFRMA_SET_MARK_MASK:
if state.OutputMark == nil {
state.OutputMark = new(XfrmMark)
}
state.OutputMark.Mask = native.Uint32(attr.Value)
if state.OutputMark.Mask == 0xffffffff {
state.OutputMark.Mask = 0
}
case nl.XFRMA_IF_ID: case nl.XFRMA_IF_ID:
state.Ifid = int(native.Uint32(attr.Value)) state.Ifid = int(native.Uint32(attr.Value))
} }

View File

@ -48,3 +48,14 @@ func main() {
} }
``` ```
## NOTE
The library can be safely used only with Go >= 1.10 due to [golang/go#20676](https://github.com/golang/go/issues/20676).
After locking a goroutine to its current OS thread with `runtime.LockOSThread()`
and changing its network namespace, any new subsequent goroutine won't be
scheduled on that thread while it's locked. Therefore, the new goroutine
will run in a different namespace leading to unexpected results.
See [here](https://www.weave.works/blog/linux-namespaces-golang-followup) for more details.

View File

@ -1,4 +1,4 @@
// +build linux // +build linux,go1.10
package netns package netns
@ -218,12 +218,18 @@ func getPidForContainer(id string) (int, error) {
filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"), filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"),
// Even more recent docker versions under cgroup/systemd/docker/<id>/ // Even more recent docker versions under cgroup/systemd/docker/<id>/
filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"), filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"),
// Kubernetes with docker and CNI is even more different // Kubernetes with docker and CNI is even more different. Works for BestEffort and Burstable QoS
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, "tasks"), filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, "tasks"),
// Another flavor of containers location in recent kubernetes 1.11+ // Same as above but for Guaranteed QoS
filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"), filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "pod*", id, "tasks"),
// When runs inside of a container with recent kubernetes 1.11+ // Another flavor of containers location in recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
filepath.Join(cgroupRoot, "kubepods.slice", "kubepods-besteffort.slice", "*", "docker-"+id+".scope", "tasks"), filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", "tasks"),
// Same as above but for Guaranteed QoS
filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "*", "docker-"+id+".scope", "tasks"),
// When runs inside of a container with recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", "tasks"),
// Same as above but for Guaranteed QoS
filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", "tasks"),
} }
var filename string var filename string

View File

@ -405,10 +405,11 @@ includes_SunOS='
#include <net/if_arp.h> #include <net/if_arp.h>
#include <net/if_types.h> #include <net/if_types.h>
#include <net/route.h> #include <net/route.h>
#include <netinet/icmp6.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <termios.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include <netinet/ip_mroute.h> #include <netinet/ip_mroute.h>
#include <termios.h>
' '
@ -499,10 +500,10 @@ ccflags="$@"
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ || $2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
$2 ~ /^LO_(KEY|NAME)_SIZE$/ || $2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
$2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ || $2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ ||
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL)_/ || $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL)_/ ||
$2 ~ /^TP_STATUS_/ || $2 ~ /^TP_STATUS_/ ||
$2 ~ /^FALLOC_/ || $2 ~ /^FALLOC_/ ||
$2 ~ /^ICMP(V6)?_FILTER$/ || $2 ~ /^ICMPV?6?_(FILTER|SEC)/ ||
$2 == "SOMAXCONN" || $2 == "SOMAXCONN" ||
$2 == "NAME_MAX" || $2 == "NAME_MAX" ||
$2 == "IFNAMSIZ" || $2 == "IFNAMSIZ" ||

View File

@ -106,6 +106,31 @@ func IoctlGetRTCTime(fd int) (*RTCTime, error) {
return &value, err return &value, err
} }
type ifreqEthtool struct {
name [IFNAMSIZ]byte
data unsafe.Pointer
}
// IoctlGetEthtoolDrvinfo fetches ethtool driver information for the network
// device specified by ifname.
func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) {
// Leave room for terminating NULL byte.
if len(ifname) >= IFNAMSIZ {
return nil, EINVAL
}
value := EthtoolDrvinfo{
Cmd: ETHTOOL_GDRVINFO,
}
ifreq := ifreqEthtool{
data: unsafe.Pointer(&value),
}
copy(ifreq.name[:], ifname)
err := ioctl(fd, SIOCETHTOOL, uintptr(unsafe.Pointer(&ifreq)))
runtime.KeepAlive(ifreq)
return &value, err
}
// IoctlGetWatchdogInfo fetches information about a watchdog device from the // IoctlGetWatchdogInfo fetches information about a watchdog device from the
// Linux watchdog API. For more information, see: // Linux watchdog API. For more information, see:
// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html. // https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
@ -857,9 +882,11 @@ type SockaddrVM struct {
// CID and Port specify a context ID and port address for a VM socket. // CID and Port specify a context ID and port address for a VM socket.
// Guests have a unique CID, and hosts may have a well-known CID of: // Guests have a unique CID, and hosts may have a well-known CID of:
// - VMADDR_CID_HYPERVISOR: refers to the hypervisor process. // - VMADDR_CID_HYPERVISOR: refers to the hypervisor process.
// - VMADDR_CID_LOCAL: refers to local communication (loopback).
// - VMADDR_CID_HOST: refers to other processes on the host. // - VMADDR_CID_HOST: refers to other processes on the host.
CID uint32 CID uint32
Port uint32 Port uint32
Flags uint8
raw RawSockaddrVM raw RawSockaddrVM
} }
@ -867,6 +894,7 @@ func (sa *SockaddrVM) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_VSOCK sa.raw.Family = AF_VSOCK
sa.raw.Port = sa.Port sa.raw.Port = sa.Port
sa.raw.Cid = sa.CID sa.raw.Cid = sa.CID
sa.raw.Flags = sa.Flags
return unsafe.Pointer(&sa.raw), SizeofSockaddrVM, nil return unsafe.Pointer(&sa.raw), SizeofSockaddrVM, nil
} }
@ -1173,6 +1201,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
sa := &SockaddrVM{ sa := &SockaddrVM{
CID: pp.Cid, CID: pp.Cid,
Port: pp.Port, Port: pp.Port,
Flags: pp.Flags,
} }
return sa, nil return sa, nil
case AF_BLUETOOTH: case AF_BLUETOOTH:

View File

@ -1022,6 +1022,15 @@ const (
MAP_RESERVED0100 = 0x100 MAP_RESERVED0100 = 0x100
MAP_SHARED = 0x1 MAP_SHARED = 0x1
MAP_STACK = 0x400 MAP_STACK = 0x400
MCAST_BLOCK_SOURCE = 0x54
MCAST_EXCLUDE = 0x2
MCAST_INCLUDE = 0x1
MCAST_JOIN_GROUP = 0x50
MCAST_JOIN_SOURCE_GROUP = 0x52
MCAST_LEAVE_GROUP = 0x51
MCAST_LEAVE_SOURCE_GROUP = 0x53
MCAST_UNBLOCK_SOURCE = 0x55
MCAST_UNDEFINED = 0x0
MCL_CURRENT = 0x1 MCL_CURRENT = 0x1
MCL_FUTURE = 0x2 MCL_FUTURE = 0x2
MNT_ACLS = 0x8000000 MNT_ACLS = 0x8000000

View File

@ -974,6 +974,10 @@ const (
HUGETLBFS_MAGIC = 0x958458f6 HUGETLBFS_MAGIC = 0x958458f6
IBSHIFT = 0x10 IBSHIFT = 0x10
ICMPV6_FILTER = 0x1 ICMPV6_FILTER = 0x1
ICMPV6_FILTER_BLOCK = 0x1
ICMPV6_FILTER_BLOCKOTHERS = 0x3
ICMPV6_FILTER_PASS = 0x2
ICMPV6_FILTER_PASSONLY = 0x4
ICMP_FILTER = 0x1 ICMP_FILTER = 0x1
ICRNL = 0x100 ICRNL = 0x100
IFA_F_DADFAILED = 0x8 IFA_F_DADFAILED = 0x8

View File

@ -366,6 +366,7 @@ const (
HUPCL = 0x400 HUPCL = 0x400
IBSHIFT = 0x10 IBSHIFT = 0x10
ICANON = 0x2 ICANON = 0x2
ICMP6_FILTER = 0x1
ICRNL = 0x100 ICRNL = 0x100
IEXTEN = 0x8000 IEXTEN = 0x8000
IFF_ADDRCONF = 0x80000 IFF_ADDRCONF = 0x80000
@ -612,6 +613,7 @@ const (
IP_RECVPKTINFO = 0x1a IP_RECVPKTINFO = 0x1a
IP_RECVRETOPTS = 0x6 IP_RECVRETOPTS = 0x6
IP_RECVSLLA = 0xa IP_RECVSLLA = 0xa
IP_RECVTOS = 0xc
IP_RECVTTL = 0xb IP_RECVTTL = 0xb
IP_RETOPTS = 0x8 IP_RETOPTS = 0x8
IP_REUSEADDR = 0x104 IP_REUSEADDR = 0x104
@ -704,6 +706,7 @@ const (
O_APPEND = 0x8 O_APPEND = 0x8
O_CLOEXEC = 0x800000 O_CLOEXEC = 0x800000
O_CREAT = 0x100 O_CREAT = 0x100
O_DIRECT = 0x2000000
O_DIRECTORY = 0x1000000 O_DIRECTORY = 0x1000000
O_DSYNC = 0x40 O_DSYNC = 0x40
O_EXCL = 0x400 O_EXCL = 0x400

View File

@ -137,6 +137,7 @@ const (
IP_TTL = 3 IP_TTL = 3
IP_UNBLOCK_SOURCE = 11 IP_UNBLOCK_SOURCE = 11
ICANON = 0x0010 ICANON = 0x0010
ICMP6_FILTER = 0x26
ICRNL = 0x0002 ICRNL = 0x0002
IEXTEN = 0x0020 IEXTEN = 0x0020
IGNBRK = 0x0004 IGNBRK = 0x0004

View File

@ -3698,6 +3698,21 @@ const (
ETHTOOL_A_TUNNEL_INFO_MAX = 0x2 ETHTOOL_A_TUNNEL_INFO_MAX = 0x2
) )
type EthtoolDrvinfo struct {
Cmd uint32
Driver [32]byte
Version [32]byte
Fw_version [32]byte
Bus_info [32]byte
Erom_version [32]byte
Reserved2 [12]byte
N_priv_flags uint32
N_stats uint32
Testinfo_len uint32
Eedump_len uint32
Regdump_len uint32
}
type ( type (
HIDRawReportDescriptor struct { HIDRawReportDescriptor struct {
Size uint32 Size uint32

View File

@ -1334,7 +1334,11 @@ func (absoluteSD *SECURITY_DESCRIPTOR) ToSelfRelative() (selfRelativeSD *SECURIT
} }
func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor() *SECURITY_DESCRIPTOR { func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor() *SECURITY_DESCRIPTOR {
sdLen := (int)(selfRelativeSD.Length()) sdLen := int(selfRelativeSD.Length())
const min = int(unsafe.Sizeof(SECURITY_DESCRIPTOR{}))
if sdLen < min {
sdLen = min
}
var src []byte var src []byte
h := (*unsafeheader.Slice)(unsafe.Pointer(&src)) h := (*unsafeheader.Slice)(unsafe.Pointer(&src))
@ -1342,7 +1346,15 @@ func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor()
h.Len = sdLen h.Len = sdLen
h.Cap = sdLen h.Cap = sdLen
dst := make([]byte, sdLen) const psize = int(unsafe.Sizeof(uintptr(0)))
var dst []byte
h = (*unsafeheader.Slice)(unsafe.Pointer(&dst))
alloc := make([]uintptr, (sdLen+psize-1)/psize)
h.Data = (*unsafeheader.Slice)(unsafe.Pointer(&alloc)).Data
h.Len = sdLen
h.Cap = sdLen
copy(dst, src) copy(dst, src)
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0])) return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0]))
} }

7
vendor/modules.txt vendored
View File

@ -136,11 +136,12 @@ github.com/safchain/ethtool
# github.com/sirupsen/logrus v1.8.1 # github.com/sirupsen/logrus v1.8.1
## explicit ## explicit
github.com/sirupsen/logrus github.com/sirupsen/logrus
# github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 # github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5
## explicit ## explicit
github.com/vishvananda/netlink github.com/vishvananda/netlink
github.com/vishvananda/netlink/nl github.com/vishvananda/netlink/nl
# github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae # github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f
## explicit
github.com/vishvananda/netns github.com/vishvananda/netns
# go.opencensus.io v0.22.3 # go.opencensus.io v0.22.3
go.opencensus.io go.opencensus.io
@ -156,7 +157,7 @@ golang.org/x/net/html/charset
golang.org/x/net/internal/iana golang.org/x/net/internal/iana
golang.org/x/net/internal/socket golang.org/x/net/internal/socket
golang.org/x/net/ipv4 golang.org/x/net/ipv4
# golang.org/x/sys v0.0.0-20210324051608-47abb6519492 # golang.org/x/sys v0.0.0-20210414055047-fe65e336abe0
## explicit ## explicit
golang.org/x/sys/internal/unsafeheader golang.org/x/sys/internal/unsafeheader
golang.org/x/sys/unix golang.org/x/sys/unix