Bump github.com/vishvananda/netlink to v1.3.1

hack/pin-dependency.sh github.com/vishvananda/netlink v1.3.1
hack/update-vendor.sh
This commit is contained in:
Adrian Moisey
2025-05-21 13:10:02 +02:00
parent c40db09a0a
commit 32c45ecf10
38 changed files with 1224 additions and 150 deletions

4
go.mod
View File

@@ -56,8 +56,8 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0
github.com/vishvananda/netlink v1.3.1-0.20250206174618-62fb240731fa
github.com/vishvananda/netns v0.0.4
github.com/vishvananda/netlink v1.3.1
github.com/vishvananda/netns v0.0.5
go.etcd.io/etcd/api/v3 v3.6.0
go.etcd.io/etcd/client/pkg/v3 v3.6.0
go.etcd.io/etcd/client/v3 v3.6.0

8
go.sum
View File

@@ -324,10 +324,10 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
github.com/vishvananda/netlink v1.3.1-0.20250206174618-62fb240731fa h1:iAhToRwOrdk+pKzclvLM7nKZhsg8f7dVrgkFccDUbUw=
github.com/vishvananda/netlink v1.3.1-0.20250206174618-62fb240731fa/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU=

View File

@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"net"
"strings"
"syscall"
"github.com/vishvananda/netlink/nl"
@@ -81,9 +80,6 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
msg.Index = uint32(addr.LinkIndex)
} else {
base := link.Attrs()
if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
return fmt.Errorf("label must begin with interface name")
}
h.ensureIndex(base)
msg.Index = uint32(base.Index)
}

View File

@@ -3,11 +3,102 @@ package netlink
import (
"errors"
"fmt"
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
// BridgeVlanTunnelShow gets vlanid-tunnelid mapping.
// Equivalent to: `bridge vlan tunnelshow`
//
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
// or incomplete.
func BridgeVlanTunnelShow() ([]nl.TunnelInfo, error) {
return pkgHandle.BridgeVlanTunnelShow()
}
func (h *Handle) BridgeVlanTunnelShow() ([]nl.TunnelInfo, error) {
req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
req.AddData(msg)
req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
return nil, executeErr
}
ret := make([]nl.TunnelInfo, 0)
for _, m := range msgs {
msg := nl.DeserializeIfInfomsg(m)
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil {
return nil, err
}
for _, attr := range attrs {
switch attr.Attr.Type {
case unix.IFLA_AF_SPEC:
nestedAttrs, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return nil, fmt.Errorf("failed to parse nested attr %v", err)
}
for _, nestAttr := range nestedAttrs {
switch nestAttr.Attr.Type {
case nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO:
ret, err = parseTunnelInfo(&nestAttr, ret)
if err != nil {
return nil, fmt.Errorf("failed to parse tunnelinfo %v", err)
}
}
}
}
}
}
return ret, executeErr
}
func parseTunnelInfo(nestAttr *syscall.NetlinkRouteAttr, results []nl.TunnelInfo) ([]nl.TunnelInfo, error) {
tunnelInfos, err := nl.ParseRouteAttr(nestAttr.Value)
if err != nil {
return nil, fmt.Errorf("failed to parse nested attr %v", err)
}
var tunnelId uint32
var vid uint16
var flag uint16
for _, tunnelInfo := range tunnelInfos {
switch tunnelInfo.Attr.Type {
case nl.IFLA_BRIDGE_VLAN_TUNNEL_ID:
tunnelId = native.Uint32(tunnelInfo.Value)
case nl.IFLA_BRIDGE_VLAN_TUNNEL_VID:
vid = native.Uint16(tunnelInfo.Value)
case nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS:
flag = native.Uint16(tunnelInfo.Value)
}
}
if flag == nl.BRIDGE_VLAN_INFO_RANGE_END {
lastTi := results[len(results)-1]
vni := lastTi.TunId + 1
for i := lastTi.Vid + 1; i < vid; i++ {
t := nl.TunnelInfo{
TunId: vni,
Vid: i,
}
results = append(results, t)
vni++
}
}
t := nl.TunnelInfo{
TunId: tunnelId,
Vid: vid,
}
results = append(results, t)
return results, nil
}
// BridgeVlanList gets a map of device id to bridge vlan infos.
// Equivalent to: `bridge vlan show`
//
@@ -61,6 +152,38 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
return ret, executeErr
}
// BridgeVlanAddTunnelInfo adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID tunnel_info id TUNID [ self ] [ master ]`
func BridgeVlanAddTunnelInfo(link Link, vid uint16, tunid uint32, self, master bool) error {
return pkgHandle.BridgeVlanAddTunnelInfo(link, vid, 0, tunid, 0, self, master)
}
// BridgeVlanAddRangeTunnelInfoRange adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID-VIDEND tunnel_info id VIN-VINEND [ self ] [ master ]`
func BridgeVlanAddRangeTunnelInfoRange(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
return pkgHandle.BridgeVlanAddTunnelInfo(link, vid, vidEnd, tunid, tunidEnd, self, master)
}
func (h *Handle) BridgeVlanAddTunnelInfo(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, vidEnd, tunid, tunidEnd, false, false, self, master)
}
// BridgeVlanDelTunnelInfo adds a new vlan filter entry
// Equivalent to: `bridge vlan del dev DEV vid VID tunnel_info id TUNID [ self ] [ master ]`
func BridgeVlanDelTunnelInfo(link Link, vid uint16, tunid uint32, self, master bool) error {
return pkgHandle.BridgeVlanDelTunnelInfo(link, vid, 0, tunid, 0, self, master)
}
// BridgeVlanDelRangeTunnelInfoRange adds a new vlan filter entry
// Equivalent to: `bridge vlan del dev DEV vid VID-VIDEND tunnel_info id VIN-VINEND [ self ] [ master ]`
func BridgeVlanDelRangeTunnelInfoRange(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
return pkgHandle.BridgeVlanDelTunnelInfo(link, vid, vidEnd, tunid, tunidEnd, self, master)
}
func (h *Handle) BridgeVlanDelTunnelInfo(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, vidEnd, tunid, tunidEnd, false, false, self, master)
}
// BridgeVlanAdd adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
func BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
@@ -70,7 +193,7 @@ func BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) err
// BridgeVlanAdd adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
func (h *Handle) BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, 0, pvid, untagged, self, master)
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, 0, 0, 0, pvid, untagged, self, master)
}
// BridgeVlanAddRange adds a new vlan filter entry
@@ -82,7 +205,7 @@ func BridgeVlanAddRange(link Link, vid, vidEnd uint16, pvid, untagged, self, mas
// BridgeVlanAddRange adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID-VIDEND [ pvid ] [ untagged ] [ self ] [ master ]`
func (h *Handle) BridgeVlanAddRange(link Link, vid, vidEnd uint16, pvid, untagged, self, master bool) error {
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, vidEnd, pvid, untagged, self, master)
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, vidEnd, 0, 0, pvid, untagged, self, master)
}
// BridgeVlanDel adds a new vlan filter entry
@@ -94,7 +217,7 @@ func BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) err
// BridgeVlanDel adds a new vlan filter entry
// Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
func (h *Handle) BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error {
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, 0, pvid, untagged, self, master)
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, 0, 0, 0, pvid, untagged, self, master)
}
// BridgeVlanDelRange adds a new vlan filter entry
@@ -106,10 +229,10 @@ func BridgeVlanDelRange(link Link, vid, vidEnd uint16, pvid, untagged, self, mas
// BridgeVlanDelRange adds a new vlan filter entry
// Equivalent to: `bridge vlan del dev DEV vid VID-VIDEND [ pvid ] [ untagged ] [ self ] [ master ]`
func (h *Handle) BridgeVlanDelRange(link Link, vid, vidEnd uint16, pvid, untagged, self, master bool) error {
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, vidEnd, pvid, untagged, self, master)
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, vidEnd, 0, 0, pvid, untagged, self, master)
}
func (h *Handle) bridgeVlanModify(cmd int, link Link, vid, vidEnd uint16, pvid, untagged, self, master bool) error {
func (h *Handle) bridgeVlanModify(cmd int, link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, pvid, untagged, self, master bool) error {
base := link.Attrs()
h.ensureIndex(base)
req := h.newNetlinkRequest(cmd, unix.NLM_F_ACK)
@@ -129,25 +252,45 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid, vidEnd uint16, pvid,
if flags > 0 {
br.AddRtAttr(nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags))
}
vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
if pvid {
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_PVID
}
if untagged {
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
}
if vidEnd != 0 {
vlanEndInfo := &nl.BridgeVlanInfo{Vid: vidEnd}
vlanEndInfo.Flags = vlanInfo.Flags
if tunid != 0 {
if tunidEnd != 0 {
tiStart := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
tiStart.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_ID, nl.Uint32Attr(tunid))
tiStart.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_VID, nl.Uint16Attr(vid))
tiStart.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, nl.Uint16Attr(nl.BRIDGE_VLAN_INFO_RANGE_BEGIN))
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_BEGIN
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
tiEnd := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
tiEnd.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_ID, nl.Uint32Attr(tunidEnd))
tiEnd.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_VID, nl.Uint16Attr(vidEnd))
tiEnd.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, nl.Uint16Attr(nl.BRIDGE_VLAN_INFO_RANGE_END))
} else {
ti := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
ti.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_ID, nl.Uint32Attr(tunid))
ti.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_VID, nl.Uint16Attr(vid))
ti.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, nl.Uint16Attr(0))
}
} else {
vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
if pvid {
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_PVID
}
if untagged {
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
}
vlanEndInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_END
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanEndInfo.Serialize())
} else {
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
if vidEnd != 0 {
vlanEndInfo := &nl.BridgeVlanInfo{Vid: vidEnd}
vlanEndInfo.Flags = vlanInfo.Flags
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_BEGIN
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
vlanEndInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_END
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanEndInfo.Serialize())
} else {
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
}
}
req.AddData(br)

View File

@@ -398,6 +398,29 @@ func NewPoliceAction() *PoliceAction {
}
}
type SampleAction struct {
ActionAttrs
Group uint32
Rate uint32
TruncSize uint32
}
func (action *SampleAction) Type() string {
return "sample"
}
func (action *SampleAction) Attrs() *ActionAttrs {
return &action.ActionAttrs
}
func NewSampleAction() *SampleAction {
return &SampleAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_PIPE,
},
}
}
// MatchAll filters match all packets
type MatchAll struct {
FilterAttrs

View File

@@ -54,25 +54,30 @@ func (filter *U32) Type() string {
type Flower struct {
FilterAttrs
DestIP net.IP
DestIPMask net.IPMask
SrcIP net.IP
SrcIPMask net.IPMask
EthType uint16
EncDestIP net.IP
EncDestIPMask net.IPMask
EncSrcIP net.IP
EncSrcIPMask net.IPMask
EncDestPort uint16
EncKeyId uint32
SrcMac net.HardwareAddr
DestMac net.HardwareAddr
VlanId uint16
SkipHw bool
SkipSw bool
IPProto *nl.IPProto
DestPort uint16
SrcPort uint16
ClassId uint32
DestIP net.IP
DestIPMask net.IPMask
SrcIP net.IP
SrcIPMask net.IPMask
EthType uint16
EncDestIP net.IP
EncDestIPMask net.IPMask
EncSrcIP net.IP
EncSrcIPMask net.IPMask
EncDestPort uint16
EncKeyId uint32
SrcMac net.HardwareAddr
DestMac net.HardwareAddr
VlanId uint16
SkipHw bool
SkipSw bool
IPProto *nl.IPProto
DestPort uint16
SrcPort uint16
SrcPortRangeMin uint16
SrcPortRangeMax uint16
DstPortRangeMin uint16
DstPortRangeMax uint16
Actions []Action
}
@@ -171,6 +176,19 @@ func (filter *Flower) encode(parent *nl.RtAttr) error {
}
}
}
if filter.SrcPortRangeMin != 0 && filter.SrcPortRangeMax != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_PORT_SRC_MIN, htons(filter.SrcPortRangeMin))
parent.AddRtAttr(nl.TCA_FLOWER_KEY_PORT_SRC_MAX, htons(filter.SrcPortRangeMax))
}
if filter.DstPortRangeMin != 0 && filter.DstPortRangeMax != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_PORT_DST_MIN, htons(filter.DstPortRangeMin))
parent.AddRtAttr(nl.TCA_FLOWER_KEY_PORT_DST_MAX, htons(filter.DstPortRangeMax))
}
if filter.ClassId != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_CLASSID, nl.Uint32Attr(filter.ClassId))
}
var flags uint32 = 0
if filter.SkipHw {
@@ -247,6 +265,16 @@ func (filter *Flower) decode(data []syscall.NetlinkRouteAttr) error {
if skipHw != 0 {
filter.SkipHw = true
}
case nl.TCA_FLOWER_KEY_PORT_SRC_MIN:
filter.SrcPortRangeMin = ntohs(datum.Value)
case nl.TCA_FLOWER_KEY_PORT_SRC_MAX:
filter.SrcPortRangeMax = ntohs(datum.Value)
case nl.TCA_FLOWER_KEY_PORT_DST_MIN:
filter.DstPortRangeMin = ntohs(datum.Value)
case nl.TCA_FLOWER_KEY_PORT_DST_MAX:
filter.DstPortRangeMax = ntohs(datum.Value)
case nl.TCA_FLOWER_CLASSID:
filter.ClassId = native.Uint32(datum.Value)
}
}
return nil
@@ -740,6 +768,17 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize())
aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
case *SampleAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("sample"))
aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
gen := nl.TcGen{}
toTcGen(action.Attrs(), &gen)
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_PARMS, gen.Serialize())
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_RATE, nl.Uint32Attr(action.Rate))
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_PSAMPLE_GROUP, nl.Uint32Attr(action.Group))
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_TRUNC_SIZE, nl.Uint32Attr(action.TruncSize))
case *GenericAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
@@ -752,6 +791,7 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
pedit := nl.TcPedit{}
toTcGen(action.Attrs(), &pedit.Sel.TcGen)
if action.SrcMacAddr != nil {
pedit.SetEthSrc(action.SrcMacAddr)
}
@@ -825,6 +865,8 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
action = &ConnmarkAction{}
case "csum":
action = &CsumAction{}
case "sample":
action = &SampleAction{}
case "gact":
action = &GenericAction{}
case "vlan":
@@ -949,6 +991,18 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
tcTs := nl.DeserializeTcf(adatum.Value)
actionTimestamp = toTimeStamp(tcTs)
}
case "sample":
switch adatum.Attr.Type {
case nl.TCA_ACT_SAMPLE_PARMS:
gen := *nl.DeserializeTcGen(adatum.Value)
toAttrs(&gen, action.Attrs())
case nl.TCA_ACT_SAMPLE_RATE:
action.(*SampleAction).Rate = native.Uint32(adatum.Value[0:4])
case nl.TCA_ACT_SAMPLE_PSAMPLE_GROUP:
action.(*SampleAction).Group = native.Uint32(adatum.Value[0:4])
case nl.TCA_ACT_SAMPLE_TRUNC_SIZE:
action.(*SampleAction).TruncSize = native.Uint32(adatum.Value[0:4])
}
case "gact":
switch adatum.Attr.Type {
case nl.TCA_GACT_PARMS:

View File

@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package netlink
@@ -183,6 +184,10 @@ func (h *Handle) LinkSetGROIPv4MaxSize(link Link, maxSize int) error {
return ErrNotImplemented
}
func (h *Handle) LinkSetIP6AddrGenMode(link Link, mode int) error {
return ErrNotImplemented
}
func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
return ErrNotImplemented
}

View File

@@ -86,5 +86,5 @@ func newIocltStringSetReq(linkName string) (*Ifreq, *ethtoolSset) {
// getSocketUDP returns file descriptor to new UDP socket
// It is used for communication with ioctl interface.
func getSocketUDP() (int, error) {
return syscall.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
return syscall.Socket(unix.AF_INET, unix.SOCK_DGRAM|unix.SOCK_CLOEXEC, 0)
}

View File

@@ -147,9 +147,11 @@ 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_TYPENAME, nl.ZeroTerminated(typename)))
cadtFlags := optionsToBitflag(options)
revision := options.Revision
if revision == 0 {
revision = getIpsetDefaultWithTypeName(typename)
revision = getIpsetDefaultRevision(typename, cadtFlags)
}
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(revision)))
@@ -181,18 +183,6 @@ func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOption
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *timeout})
}
var cadtFlags uint32
if options.Comments {
cadtFlags |= nl.IPSET_FLAG_WITH_COMMENT
}
if options.Counters {
cadtFlags |= nl.IPSET_FLAG_WITH_COUNTERS
}
if options.Skbinfo {
cadtFlags |= nl.IPSET_FLAG_WITH_SKBINFO
}
if cadtFlags != 0 {
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER, Value: cadtFlags})
}
@@ -395,14 +385,89 @@ func (h *Handle) newIpsetRequest(cmd int) *nl.NetlinkRequest {
return req
}
func getIpsetDefaultWithTypeName(typename string) uint8 {
// NOTE: This can't just take typename into account, it also has to take desired
// feature support into account, on a per-set-type basis, to return the correct revision, see e.g.
// https://github.com/Olipro/ipset/blob/9f145b49100104d6570fe5c31a5236816ebb4f8f/kernel/net/netfilter/ipset/ip_set_hash_ipport.c#L30
//
// This means that whenever a new "type" of ipset is added, returning the "correct" default revision
// requires adding a new case here for that type, and consulting the ipset C code to figure out the correct
// combination of type name, feature bit flags, and revision ranges.
//
// Care should be taken as some types share the same revision ranges for the same features, and others do not.
// When in doubt, mimic the C code.
func getIpsetDefaultRevision(typename string, featureFlags uint32) uint8 {
switch typename {
case "hash:ip,port",
"hash:ip,port,ip",
"hash:ip,port,net",
"hash:ip,port,ip":
// Taken from
// - ipset/kernel/net/netfilter/ipset/ip_set_hash_ipport.c
// - ipset/kernel/net/netfilter/ipset/ip_set_hash_ipportip.c
if (featureFlags & nl.IPSET_FLAG_WITH_SKBINFO) != 0 {
return 5
}
if (featureFlags & nl.IPSET_FLAG_WITH_FORCEADD) != 0 {
return 4
}
if (featureFlags & nl.IPSET_FLAG_WITH_COMMENT) != 0 {
return 3
}
if (featureFlags & nl.IPSET_FLAG_WITH_COUNTERS) != 0 {
return 2
}
// the min revision this library supports for this type
return 1
case "hash:ip,port,net",
"hash:net,port":
// Taken from
// - ipset/kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
// - ipset/kernel/net/netfilter/ipset/ip_set_hash_netport.c
if (featureFlags & nl.IPSET_FLAG_WITH_SKBINFO) != 0 {
return 7
}
if (featureFlags & nl.IPSET_FLAG_WITH_FORCEADD) != 0 {
return 6
}
if (featureFlags & nl.IPSET_FLAG_WITH_COMMENT) != 0 {
return 5
}
if (featureFlags & nl.IPSET_FLAG_WITH_COUNTERS) != 0 {
return 4
}
if (featureFlags & nl.IPSET_FLAG_NOMATCH) != 0 {
return 3
}
// the min revision this library supports for this type
return 2
case "hash:ip":
// Taken from
// - ipset/kernel/net/netfilter/ipset/ip_set_hash_ip.c
if (featureFlags & nl.IPSET_FLAG_WITH_SKBINFO) != 0 {
return 4
}
if (featureFlags & nl.IPSET_FLAG_WITH_FORCEADD) != 0 {
return 3
}
if (featureFlags & nl.IPSET_FLAG_WITH_COMMENT) != 0 {
return 2
}
// the min revision this library supports for this type
return 1
}
// can't map the correct revision for this type.
return 0
}
@@ -579,3 +644,19 @@ func parseIPSetEntry(data []byte) (entry IPSetEntry) {
}
return
}
func optionsToBitflag(options IpsetCreateOptions) uint32 {
var cadtFlags uint32
if options.Comments {
cadtFlags |= nl.IPSET_FLAG_WITH_COMMENT
}
if options.Counters {
cadtFlags |= nl.IPSET_FLAG_WITH_COUNTERS
}
if options.Skbinfo {
cadtFlags |= nl.IPSET_FLAG_WITH_SKBINFO
}
return cadtFlags
}

View File

@@ -290,8 +290,15 @@ func (bridge *Bridge) Type() string {
// Vlan links have ParentIndex set in their Attrs()
type Vlan struct {
LinkAttrs
VlanId int
VlanProtocol VlanProtocol
VlanId int
VlanProtocol VlanProtocol
IngressQosMap map[uint32]uint32
EgressQosMap map[uint32]uint32
ReorderHdr *bool
Gvrp *bool
LooseBinding *bool
Mvrp *bool
BridgeBinding *bool
}
func (vlan *Vlan) Attrs() *LinkAttrs {
@@ -348,13 +355,14 @@ type TuntapFlag uint16
// Tuntap links created via /dev/tun/tap, but can be destroyed via netlink
type Tuntap struct {
LinkAttrs
Mode TuntapMode
Flags TuntapFlag
NonPersist bool
Queues int
Fds []*os.File
Owner uint32
Group uint32
Mode TuntapMode
Flags TuntapFlag
NonPersist bool
Queues int
DisabledQueues int
Fds []*os.File
Owner uint32
Group uint32
}
func (tuntap *Tuntap) Attrs() *LinkAttrs {
@@ -425,6 +433,17 @@ type Veth struct {
PeerName string // veth on create only
PeerHardwareAddr net.HardwareAddr
PeerNamespace interface{}
PeerTxQLen int
PeerNumTxQueues uint32
PeerNumRxQueues uint32
PeerMTU uint32
}
func NewVeth(attr LinkAttrs) *Veth {
return &Veth{
LinkAttrs: attr,
PeerTxQLen: -1,
}
}
func (veth *Veth) Attrs() *LinkAttrs {
@@ -1058,6 +1077,8 @@ type Geneve struct {
FlowBased bool
InnerProtoInherit bool
Df GeneveDf
PortLow int
PortHigh int
}
func (geneve *Geneve) Attrs() *LinkAttrs {

View File

@@ -1683,6 +1683,73 @@ func (h *Handle) linkModify(link Link, flags int) error {
native.PutUint16(b, uint16(link.VlanId))
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_VLAN_ID, b)
var vlanFlags uint32
var vlanFlagsMask uint32
if link.ReorderHdr != nil {
vlanFlagsMask |= nl.VLAN_FLAG_REORDER_HDR
if *link.ReorderHdr {
vlanFlags |= nl.VLAN_FLAG_REORDER_HDR
} else {
vlanFlags &= ^uint32(nl.VLAN_FLAG_REORDER_HDR)
}
}
if link.Gvrp != nil {
vlanFlagsMask |= nl.VLAN_FLAG_GVRP
if *link.Gvrp {
vlanFlags |= nl.VLAN_FLAG_GVRP
} else {
vlanFlags &= ^uint32(nl.VLAN_FLAG_GVRP)
}
}
if link.Mvrp != nil {
vlanFlagsMask |= nl.VLAN_FLAG_MVRP
if *link.Mvrp {
vlanFlags |= nl.VLAN_FLAG_MVRP
} else {
vlanFlags &= ^uint32(nl.VLAN_FLAG_MVRP)
}
}
if link.LooseBinding != nil {
vlanFlagsMask |= nl.VLAN_FLAG_LOOSE_BINDING
if *link.LooseBinding {
vlanFlags |= nl.VLAN_FLAG_LOOSE_BINDING
} else {
vlanFlags &= ^uint32(nl.VLAN_FLAG_LOOSE_BINDING)
}
}
if link.BridgeBinding != nil {
vlanFlagsMask |= nl.VLAN_FLAG_BRIDGE_BINDING
if *link.BridgeBinding {
vlanFlags |= nl.VLAN_FLAG_BRIDGE_BINDING
} else {
vlanFlags &= ^uint32(nl.VLAN_FLAG_BRIDGE_BINDING)
}
}
buf := &bytes.Buffer{}
buf.Write(nl.Uint32Attr(vlanFlags))
buf.Write(nl.Uint32Attr(vlanFlagsMask))
data.AddRtAttr(nl.IFLA_VLAN_FLAGS, buf.Bytes())
if link.IngressQosMap != nil {
ingressMap := data.AddRtAttr(nl.IFLA_VLAN_INGRESS_QOS, nil)
for from, to := range link.IngressQosMap {
buf := &bytes.Buffer{}
buf.Write(nl.Uint32Attr(from))
buf.Write(nl.Uint32Attr(to))
ingressMap.AddRtAttr(nl.IFLA_VLAN_QOS_MAPPING, buf.Bytes())
}
}
if link.EgressQosMap != nil {
egressMap := data.AddRtAttr(nl.IFLA_VLAN_EGRESS_QOS, nil)
for from, to := range link.EgressQosMap {
buf := &bytes.Buffer{}
buf.Write(nl.Uint32Attr(from))
buf.Write(nl.Uint32Attr(to))
egressMap.AddRtAttr(nl.IFLA_VLAN_QOS_MAPPING, buf.Bytes())
}
}
if link.VlanProtocol != VLAN_PROTOCOL_UNKNOWN {
data.AddRtAttr(nl.IFLA_VLAN_PROTOCOL, htons(uint16(link.VlanProtocol)))
@@ -1696,16 +1763,25 @@ func (h *Handle) linkModify(link Link, flags int) error {
peer := data.AddRtAttr(nl.VETH_INFO_PEER, nil)
nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC)
peer.AddRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName))
if base.TxQLen >= 0 {
if link.PeerTxQLen >= 0 {
peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(link.PeerTxQLen)))
} else if base.TxQLen >= 0 {
peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
}
if base.NumTxQueues > 0 {
if link.PeerNumTxQueues > 0 {
peer.AddRtAttr(unix.IFLA_NUM_TX_QUEUES, nl.Uint32Attr(link.PeerNumTxQueues))
} else if base.NumTxQueues > 0 {
peer.AddRtAttr(unix.IFLA_NUM_TX_QUEUES, nl.Uint32Attr(uint32(base.NumTxQueues)))
}
if base.NumRxQueues > 0 {
if link.PeerNumRxQueues > 0 {
peer.AddRtAttr(unix.IFLA_NUM_RX_QUEUES, nl.Uint32Attr(link.PeerNumRxQueues))
} else if base.NumRxQueues > 0 {
peer.AddRtAttr(unix.IFLA_NUM_RX_QUEUES, nl.Uint32Attr(uint32(base.NumRxQueues)))
}
if base.MTU > 0 {
if link.PeerMTU > 0 {
peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(link.PeerMTU))
} else if base.MTU > 0 {
peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
}
if link.PeerHardwareAddr != nil {
@@ -2544,6 +2620,14 @@ func (h *Handle) LinkSetLearning(link Link, mode bool) error {
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING)
}
func LinkSetVlanTunnel(link Link, mode bool) error {
return pkgHandle.LinkSetVlanTunnel(link, mode)
}
func (h *Handle) LinkSetVlanTunnel(link Link, mode bool) error {
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_VLAN_TUNNEL)
}
func LinkSetRootBlock(link Link, mode bool) error {
return pkgHandle.LinkSetRootBlock(link, mode)
}
@@ -2670,9 +2754,38 @@ func (h *Handle) LinkSetGroup(link Link, group int) error {
return err
}
// LinkSetIP6AddrGenMode sets the IPv6 address generation mode of the link device.
// Equivalent to: `ip link set $link addrgenmode $mode`
func LinkSetIP6AddrGenMode(link Link, mode int) error {
return pkgHandle.LinkSetIP6AddrGenMode(link, mode)
}
// LinkSetIP6AddrGenMode sets the IPv6 address generation mode of the link device.
// Equivalent to: `ip link set $link addrgenmode $mode`
func (h *Handle) LinkSetIP6AddrGenMode(link Link, mode int) error {
base := link.Attrs()
h.ensureIndex(base)
req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Index = int32(base.Index)
req.AddData(msg)
b := make([]byte, 1)
b[0] = uint8(mode)
data := nl.NewRtAttr(unix.IFLA_INET6_ADDR_GEN_MODE, b)
af := nl.NewRtAttr(unix.AF_INET6, data.Serialize())
spec := nl.NewRtAttr(unix.IFLA_AF_SPEC, af.Serialize())
req.AddData(spec)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
func addNetkitAttrs(nk *Netkit, linkInfo *nl.RtAttr, flag int) error {
if nk.peerLinkAttrs.HardwareAddr != nil || nk.HardwareAddr != nil {
return fmt.Errorf("netkit doesn't support setting Ethernet")
if nk.Mode != NETKIT_MODE_L2 && (nk.LinkAttrs.HardwareAddr != nil || nk.peerLinkAttrs.HardwareAddr != nil) {
return fmt.Errorf("netkit only allows setting Ethernet in L2 mode")
}
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
@@ -2724,6 +2837,9 @@ func addNetkitAttrs(nk *Netkit, linkInfo *nl.RtAttr, flag int) error {
peer.AddRtAttr(unix.IFLA_NET_NS_FD, nl.Uint32Attr(uint32(ns)))
}
}
if nk.peerLinkAttrs.HardwareAddr != nil {
peer.AddRtAttr(unix.IFLA_ADDRESS, []byte(nk.peerLinkAttrs.HardwareAddr))
}
return nil
}
@@ -2752,12 +2868,65 @@ func parseNetkitData(link Link, data []syscall.NetlinkRouteAttr) {
}
}
func parseVlanQosMap(data []byte) map[uint32]uint32 {
values, err := nl.ParseRouteAttr(data)
if err != nil {
return nil
}
qosMap := make(map[uint32]uint32)
for _, value := range values {
switch value.Attr.Type {
case nl.IFLA_VLAN_QOS_MAPPING:
from := native.Uint32(value.Value[:4])
to := native.Uint32(value.Value[4:])
qosMap[from] = to
}
}
return qosMap
}
func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
vlan := link.(*Vlan)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_VLAN_ID:
vlan.VlanId = int(native.Uint16(datum.Value[0:2]))
case nl.IFLA_VLAN_FLAGS:
flags := native.Uint32(datum.Value[0:4])
trueVal := true
falseVal := false
if flags&nl.VLAN_FLAG_REORDER_HDR != 0 {
vlan.ReorderHdr = &trueVal
} else {
vlan.ReorderHdr = &falseVal
}
if flags&nl.VLAN_FLAG_GVRP != 0 {
vlan.Gvrp = &trueVal
} else {
vlan.Gvrp = &falseVal
}
if flags&nl.VLAN_FLAG_LOOSE_BINDING != 0 {
vlan.LooseBinding = &trueVal
} else {
vlan.LooseBinding = &falseVal
}
if flags&nl.VLAN_FLAG_MVRP != 0 {
vlan.Mvrp = &trueVal
} else {
vlan.Mvrp = &falseVal
}
if flags&nl.VLAN_FLAG_BRIDGE_BINDING != 0 {
vlan.BridgeBinding = &trueVal
} else {
vlan.BridgeBinding = &falseVal
}
case nl.IFLA_VLAN_EGRESS_QOS:
vlan.EgressQosMap = parseVlanQosMap(datum.Value)
case nl.IFLA_VLAN_INGRESS_QOS:
vlan.IngressQosMap = parseVlanQosMap(datum.Value)
case nl.IFLA_VLAN_PROTOCOL:
vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2])))
}
@@ -2821,7 +2990,7 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_VXLAN_PORT_RANGE:
buf := bytes.NewBuffer(datum.Value[0:4])
var pr vxlanPortRange
if binary.Read(buf, binary.BigEndian, &pr) != nil {
if binary.Read(buf, binary.BigEndian, &pr) == nil {
vxlan.PortLow = int(pr.Lo)
vxlan.PortHigh = int(pr.Hi)
}
@@ -3068,6 +3237,10 @@ func linkFlags(rawFlags uint32) net.Flags {
return f
}
type genevePortRange struct {
Lo, Hi uint16
}
func addGeneveAttrs(geneve *Geneve, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
@@ -3104,6 +3277,15 @@ func addGeneveAttrs(geneve *Geneve, linkInfo *nl.RtAttr) {
data.AddRtAttr(nl.IFLA_GENEVE_TOS, nl.Uint8Attr(geneve.Tos))
}
if geneve.PortLow > 0 || geneve.PortHigh > 0 {
pr := genevePortRange{uint16(geneve.PortLow), uint16(geneve.PortHigh)}
buf := new(bytes.Buffer)
binary.Write(buf, binary.BigEndian, &pr)
data.AddRtAttr(nl.IFLA_GENEVE_PORT_RANGE, buf.Bytes())
}
data.AddRtAttr(nl.IFLA_GENEVE_DF, nl.Uint8Attr(uint8(geneve.Df)))
}
@@ -3125,6 +3307,13 @@ func parseGeneveData(link Link, data []syscall.NetlinkRouteAttr) {
geneve.FlowBased = true
case nl.IFLA_GENEVE_INNER_PROTO_INHERIT:
geneve.InnerProtoInherit = true
case nl.IFLA_GENEVE_PORT_RANGE:
buf := bytes.NewBuffer(datum.Value[0:4])
var pr genevePortRange
if binary.Read(buf, binary.BigEndian, &pr) == nil {
geneve.PortLow = int(pr.Lo)
geneve.PortHigh = int(pr.Hi)
}
}
}
}
@@ -3900,11 +4089,27 @@ func parseTuntapData(link Link, data []syscall.NetlinkRouteAttr) {
tuntap.Group = native.Uint32(datum.Value)
case nl.IFLA_TUN_TYPE:
tuntap.Mode = TuntapMode(uint8(datum.Value[0]))
case nl.IFLA_TUN_PI:
if datum.Value[0] == 0 {
tuntap.Flags |= TUNTAP_NO_PI
}
case nl.IFLA_TUN_VNET_HDR:
if datum.Value[0] == 1 {
tuntap.Flags |= TUNTAP_VNET_HDR
}
case nl.IFLA_TUN_PERSIST:
tuntap.NonPersist = false
if uint8(datum.Value[0]) == 0 {
tuntap.NonPersist = true
}
case nl.IFLA_TUN_MULTI_QUEUE:
if datum.Value[0] == 1 {
tuntap.Flags |= TUNTAP_MULTI_QUEUE
}
case nl.IFLA_TUN_NUM_QUEUES:
tuntap.Queues = int(native.Uint32(datum.Value))
case nl.IFLA_TUN_NUM_DISABLED_QUEUES:
tuntap.DisabledQueues = int(native.Uint32(datum.Value))
}
}
}

View File

@@ -1,5 +1,14 @@
package netlink
import (
"fmt"
"os"
"strings"
"syscall"
"golang.org/x/sys/unix"
)
// ideally golang.org/x/sys/unix would define IfReq but it only has
// IFNAMSIZ, hence this minimalistic implementation
const (
@@ -7,8 +16,136 @@ const (
IFNAMSIZ = 16
)
const TUN = "/dev/net/tun"
type ifReq struct {
Name [IFNAMSIZ]byte
Flags uint16
pad [SizeOfIfReq - IFNAMSIZ - 2]byte
}
// AddQueues opens and attaches multiple queue file descriptors to an existing
// TUN/TAP interface in multi-queue mode.
//
// It performs TUNSETIFF ioctl on each opened file descriptor with the current
// tuntap configuration. Each resulting fd is set to non-blocking mode and
// returned as *os.File.
//
// If the interface was created with a name pattern (e.g. "tap%d"),
// the first successful TUNSETIFF call will return the resolved name,
// which is saved back into tuntap.Name.
//
// This method assumes that the interface already exists and is in multi-queue mode.
// The returned FDs are also appended to tuntap.Fds and tuntap.Queues is updated.
//
// It is the caller's responsibility to close the FDs when they are no longer needed.
func (tuntap *Tuntap) AddQueues(count int) ([]*os.File, error) {
if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP {
return nil, fmt.Errorf("Tuntap.Mode %v unknown", tuntap.Mode)
}
if tuntap.Flags&TUNTAP_MULTI_QUEUE == 0 {
return nil, fmt.Errorf("TUNTAP_MULTI_QUEUE not set")
}
if count < 1 {
return nil, fmt.Errorf("count must be >= 1")
}
req, err := unix.NewIfreq(tuntap.Name)
if err != nil {
return nil, err
}
req.SetUint16(uint16(tuntap.Mode) | uint16(tuntap.Flags))
var fds []*os.File
for i := 0; i < count; i++ {
localReq := req
fd, err := unix.Open(TUN, os.O_RDWR|syscall.O_CLOEXEC, 0)
if err != nil {
cleanupFds(fds)
return nil, err
}
err = unix.IoctlIfreq(fd, unix.TUNSETIFF, req)
if err != nil {
// close the new fd
unix.Close(fd)
// and the already opened ones
cleanupFds(fds)
return nil, fmt.Errorf("tuntap IOCTL TUNSETIFF failed [%d]: %w", i, err)
}
// Set the tun device to non-blocking before use. The below comment
// taken from:
//
// https://github.com/mistsys/tuntap/commit/161418c25003bbee77d085a34af64d189df62bea
//
// Note there is a complication because in go, if a device node is
// opened, go sets it to use nonblocking I/O. However a /dev/net/tun
// doesn't work with epoll until after the TUNSETIFF ioctl has been
// done. So we open the unix fd directly, do the ioctl, then put the
// fd in nonblocking mode, an then finally wrap it in a os.File,
// which will see the nonblocking mode and add the fd to the
// pollable set, so later on when we Read() from it blocked the
// calling thread in the kernel.
//
// See
// https://github.com/golang/go/issues/30426
// which got exposed in go 1.13 by the fix to
// https://github.com/golang/go/issues/30624
err = unix.SetNonblock(fd, true)
if err != nil {
cleanupFds(fds)
return nil, fmt.Errorf("tuntap set to non-blocking failed [%d]: %w", i, err)
}
// create the file from the file descriptor and store it
file := os.NewFile(uintptr(fd), TUN)
fds = append(fds, file)
// 1) we only care for the name of the first tap in the multi queue set
// 2) if the original name was empty, the localReq has now the actual name
//
// In addition:
// This ensures that the link name is always identical to what the kernel returns.
// Not only in case of an empty name, but also when using name templates.
// e.g. when the provided name is "tap%d", the kernel replaces %d with the next available number.
if i == 0 {
tuntap.Name = strings.Trim(localReq.Name(), "\x00")
}
}
tuntap.Fds = append(tuntap.Fds, fds...)
tuntap.Queues = len(tuntap.Fds)
return fds, nil
}
// RemoveQueues closes the given TAP queue file descriptors and removes them
// from the tuntap.Fds list.
//
// This is a logical counterpart to AddQueues and allows releasing specific queues
// (e.g., to simulate queue failure or perform partial detach).
//
// The method updates tuntap.Queues to reflect the number of remaining active queues.
//
// It is safe to call with a subset of tuntap.Fds, but the caller must ensure
// that the passed *os.File descriptors belong to this interface.
func (tuntap *Tuntap) RemoveQueues(fds ...*os.File) error {
toClose := make(map[uintptr]struct{}, len(fds))
for _, fd := range fds {
toClose[fd.Fd()] = struct{}{}
}
var newFds []*os.File
for _, fd := range tuntap.Fds {
if _, shouldClose := toClose[fd.Fd()]; shouldClose {
if err := fd.Close(); err != nil {
return fmt.Errorf("failed to close queue fd %d: %w", fd.Fd(), err)
}
tuntap.Queues--
} else {
newFds = append(newFds, fd)
}
}
tuntap.Fds = newFds
return nil
}

View File

@@ -19,6 +19,14 @@ type Neigh struct {
Vlan int
VNI int
MasterIndex int
// These values are expressed as "clock ticks ago". To
// convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK).
// When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed
// in centiseconds.
Confirmed uint32 // The last time ARP/ND succeeded OR higher layer confirmation was received
Used uint32 // The last time ARP/ND took place for this neighbor
Updated uint32 // The time when the current NUD state was entered
}
// String returns $ip/$hwaddr $label

View File

@@ -349,6 +349,10 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
neigh.VNI = int(native.Uint32(attr.Value[0:4]))
case NDA_MASTER:
neigh.MasterIndex = int(native.Uint32(attr.Value[0:4]))
case NDA_CACHEINFO:
neigh.Confirmed = native.Uint32(attr.Value[0:4])
neigh.Used = native.Uint32(attr.Value[4:8])
neigh.Updated = native.Uint32(attr.Value[8:12])
}
}

View File

@@ -1,3 +1,4 @@
//go:build !linux
// +build !linux
package netlink
@@ -144,6 +145,10 @@ func LinkSetGROIPv4MaxSize(link Link, maxSize int) error {
return ErrNotImplemented
}
func LinkSetIP6AddrGenMode(link Link, mode int) error {
return ErrNotImplemented
}
func LinkAdd(link Link) error {
return ErrNotImplemented
}

View File

@@ -26,6 +26,14 @@ const (
IFLA_BRIDGE_FLAGS = iota
IFLA_BRIDGE_MODE
IFLA_BRIDGE_VLAN_INFO
IFLA_BRIDGE_VLAN_TUNNEL_INFO
)
const (
IFLA_BRIDGE_VLAN_TUNNEL_UNSPEC = iota
IFLA_BRIDGE_VLAN_TUNNEL_ID
IFLA_BRIDGE_VLAN_TUNNEL_VID
IFLA_BRIDGE_VLAN_TUNNEL_FLAGS
)
const (
@@ -41,6 +49,11 @@ const (
// __u16 vid;
// };
type TunnelInfo struct {
TunId uint32
Vid uint16
}
type BridgeVlanInfo struct {
Flags uint16
Vid uint16

View File

@@ -31,6 +31,20 @@ const (
IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL
)
const (
IFLA_VLAN_QOS_UNSPEC = iota
IFLA_VLAN_QOS_MAPPING
IFLA_VLAN_QOS_MAX = IFLA_VLAN_QOS_MAPPING
)
const (
VLAN_FLAG_REORDER_HDR = 1 << iota
VLAN_FLAG_GVRP
VLAN_FLAG_LOOSE_BINDING
VLAN_FLAG_MVRP
VLAN_FLAG_BRIDGE_BINDING
)
const (
IFLA_NETKIT_UNSPEC = iota
IFLA_NETKIT_PEER_INFO
@@ -234,6 +248,7 @@ const (
IFLA_GENEVE_TTL_INHERIT
IFLA_GENEVE_DF
IFLA_GENEVE_INNER_PROTO_INHERIT
IFLA_GENEVE_PORT_RANGE
IFLA_GENEVE_MAX = IFLA_GENEVE_INNER_PROTO_INHERIT
)
@@ -818,3 +833,10 @@ const (
IFLA_BAREUDP_MULTIPROTO_MODE
IFLA_BAREUDP_MAX = IFLA_BAREUDP_MULTIPROTO_MODE
)
const (
IN6_ADDR_GEN_MODE_EUI64 = iota
IN6_ADDR_GEN_MODE_NONE
IN6_ADDR_GEN_MODE_STABLE_PRIVACY
IN6_ADDR_GEN_MODE_RANDOM
)

View File

@@ -789,7 +789,7 @@ func executeInNetns(newNs, curNs netns.NsHandle) (func(), error) {
// Returns the netlink socket on which Receive() method can be called
// to retrieve the messages from the kernel.
func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW, protocol)
fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW|unix.SOCK_CLOEXEC, protocol)
if err != nil {
return nil, err
}

View File

@@ -17,7 +17,7 @@ func ParseAttributes(data []byte) <-chan Attribute {
go func() {
i := 0
for i+4 < len(data) {
for i+4 <= len(data) {
length := int(native.Uint16(data[i : i+2]))
attrType := native.Uint16(data[i+2 : i+4])

View File

@@ -9,31 +9,41 @@ const (
)
const (
RDMA_NLDEV_CMD_GET = 1
RDMA_NLDEV_CMD_SET = 2
RDMA_NLDEV_CMD_NEWLINK = 3
RDMA_NLDEV_CMD_DELLINK = 4
RDMA_NLDEV_CMD_SYS_GET = 6
RDMA_NLDEV_CMD_SYS_SET = 7
RDMA_NLDEV_CMD_GET = 1
RDMA_NLDEV_CMD_SET = 2
RDMA_NLDEV_CMD_NEWLINK = 3
RDMA_NLDEV_CMD_DELLINK = 4
RDMA_NLDEV_CMD_SYS_GET = 6
RDMA_NLDEV_CMD_SYS_SET = 7
RDMA_NLDEV_CMD_RES_GET = 9
RDMA_NLDEV_CMD_STAT_GET = 17
)
const (
RDMA_NLDEV_ATTR_DEV_INDEX = 1
RDMA_NLDEV_ATTR_DEV_NAME = 2
RDMA_NLDEV_ATTR_PORT_INDEX = 3
RDMA_NLDEV_ATTR_CAP_FLAGS = 4
RDMA_NLDEV_ATTR_FW_VERSION = 5
RDMA_NLDEV_ATTR_NODE_GUID = 6
RDMA_NLDEV_ATTR_SYS_IMAGE_GUID = 7
RDMA_NLDEV_ATTR_SUBNET_PREFIX = 8
RDMA_NLDEV_ATTR_LID = 9
RDMA_NLDEV_ATTR_SM_LID = 10
RDMA_NLDEV_ATTR_LMC = 11
RDMA_NLDEV_ATTR_PORT_STATE = 12
RDMA_NLDEV_ATTR_PORT_PHYS_STATE = 13
RDMA_NLDEV_ATTR_DEV_NODE_TYPE = 14
RDMA_NLDEV_ATTR_NDEV_NAME = 51
RDMA_NLDEV_ATTR_LINK_TYPE = 65
RDMA_NLDEV_SYS_ATTR_NETNS_MODE = 66
RDMA_NLDEV_NET_NS_FD = 68
RDMA_NLDEV_ATTR_DEV_INDEX = 1
RDMA_NLDEV_ATTR_DEV_NAME = 2
RDMA_NLDEV_ATTR_PORT_INDEX = 3
RDMA_NLDEV_ATTR_CAP_FLAGS = 4
RDMA_NLDEV_ATTR_FW_VERSION = 5
RDMA_NLDEV_ATTR_NODE_GUID = 6
RDMA_NLDEV_ATTR_SYS_IMAGE_GUID = 7
RDMA_NLDEV_ATTR_SUBNET_PREFIX = 8
RDMA_NLDEV_ATTR_LID = 9
RDMA_NLDEV_ATTR_SM_LID = 10
RDMA_NLDEV_ATTR_LMC = 11
RDMA_NLDEV_ATTR_PORT_STATE = 12
RDMA_NLDEV_ATTR_PORT_PHYS_STATE = 13
RDMA_NLDEV_ATTR_DEV_NODE_TYPE = 14
RDMA_NLDEV_ATTR_RES_SUMMARY = 15
RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY = 16
RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME = 17
RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR = 18
RDMA_NLDEV_ATTR_NDEV_NAME = 51
RDMA_NLDEV_ATTR_LINK_TYPE = 65
RDMA_NLDEV_SYS_ATTR_NETNS_MODE = 66
RDMA_NLDEV_NET_NS_FD = 68
RDMA_NLDEV_ATTR_STAT_HWCOUNTERS = 80
RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY = 81
RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME = 82
RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE = 83
)

View File

@@ -13,6 +13,7 @@ const (
SEG6_LOCAL_IIF
SEG6_LOCAL_OIF
SEG6_LOCAL_BPF
SEG6_LOCAL_VRFTABLE
__SEG6_LOCAL_MAX
)
const (

View File

@@ -77,6 +77,17 @@ const (
TCA_ACT_MAX
)
const (
TCA_ACT_SAMPLE_UNSPEC = iota
TCA_ACT_SAMPLE_TM
TCA_ACT_SAMPLE_PARMS
TCA_ACT_SAMPLE_RATE
TCA_ACT_SAMPLE_TRUNC_SIZE
TCA_ACT_SAMPLE_PSAMPLE_GROUP
TCA_ACT_SAMPLE_PAD
TCA_ACT_SAMPLE_MAX
)
const (
TCA_PRIO_UNSPEC = iota
TCA_PRIO_MQ
@@ -1112,6 +1123,13 @@ const (
TCA_FLOWER_KEY_ENC_OPTS
TCA_FLOWER_KEY_ENC_OPTS_MASK
TCA_FLOWER_IN_HW_COUNT
TCA_FLOWER_KEY_PORT_SRC_MIN /* be16 */
TCA_FLOWER_KEY_PORT_SRC_MAX /* be16 */
TCA_FLOWER_KEY_PORT_DST_MIN /* be16 */
TCA_FLOWER_KEY_PORT_DST_MAX /* be16 */
__TCA_FLOWER_MAX
)
@@ -1127,11 +1145,11 @@ const TCA_CLS_FLAGS_SKIP_SW = 1 << 1 /* don't use filter in SW */
// };
type TcSfqQopt struct {
Quantum uint8
Quantum uint32
Perturb int32
Limit uint32
Divisor uint8
Flows uint8
Divisor uint32
Flows uint32
}
func (x *TcSfqQopt) Len() int {
@@ -1569,7 +1587,7 @@ func (p *TcPedit) SetIPv6Dst(ip6 net.IP) {
}
func (p *TcPedit) SetIPv4Src(ip net.IP) {
u32 := NativeEndian().Uint32(ip[:4])
u32 := NativeEndian().Uint32(ip.To4())
tKey := TcPeditKey{}
tKeyEx := TcPeditKeyEx{}
@@ -1585,7 +1603,7 @@ func (p *TcPedit) SetIPv4Src(ip net.IP) {
}
func (p *TcPedit) SetIPv4Dst(ip net.IP) {
u32 := NativeEndian().Uint32(ip[:4])
u32 := NativeEndian().Uint32(ip.To4())
tKey := TcPeditKey{}
tKeyEx := TcPeditKeyEx{}

View File

@@ -78,10 +78,14 @@ const (
XFRMA_PROTO /* __u8 */
XFRMA_ADDRESS_FILTER /* struct xfrm_address_filter */
XFRMA_PAD
XFRMA_OFFLOAD_DEV /* struct xfrm_state_offload */
XFRMA_SET_MARK /* __u32 */
XFRMA_SET_MARK_MASK /* __u32 */
XFRMA_IF_ID /* __u32 */
XFRMA_OFFLOAD_DEV /* struct xfrm_state_offload */
XFRMA_SET_MARK /* __u32 */
XFRMA_SET_MARK_MASK /* __u32 */
XFRMA_IF_ID /* __u32 */
XFRMA_MTIMER_THRESH /* __u32 in seconds for input SA */
XFRMA_SA_DIR /* __u8 */
XFRMA_NAT_KEEPALIVE_INTERVAL /* __u32 in seconds for NAT keepalive */
XFRMA_SA_PCPU /* __u32 */
XFRMA_MAX = iota - 1
)

View File

@@ -16,6 +16,7 @@ type Protinfo struct {
ProxyArpWiFi bool
Isolated bool
NeighSuppress bool
VlanTunnel bool
}
// String returns a list of enabled flags
@@ -55,6 +56,9 @@ func (prot *Protinfo) String() string {
if prot.NeighSuppress {
boolStrings = append(boolStrings, "NeighSuppress")
}
if prot.VlanTunnel {
boolStrings = append(boolStrings, "VlanTunnel")
}
return strings.Join(boolStrings, " ")
}

View File

@@ -77,7 +77,10 @@ func parseProtinfo(infos []syscall.NetlinkRouteAttr) (pi Protinfo) {
pi.Isolated = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_NEIGH_SUPPRESS:
pi.NeighSuppress = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_VLAN_TUNNEL:
pi.VlanTunnel = byteToBool(info.Value[0])
}
}
return
}

View File

@@ -374,10 +374,10 @@ func (qdisc *FqCodel) Type() string {
type Sfq struct {
QdiscAttrs
// TODO: Only the simplified options for SFQ are handled here. Support for the extended one can be added later.
Quantum uint8
Perturb uint8
Quantum uint32
Perturb int32
Limit uint32
Divisor uint8
Divisor uint32
}
func (sfq *Sfq) String() string {

View File

@@ -321,7 +321,7 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
case *Sfq:
opt := nl.TcSfqQoptV1{}
opt.TcSfqQopt.Quantum = qdisc.Quantum
opt.TcSfqQopt.Perturb = int32(qdisc.Perturb)
opt.TcSfqQopt.Perturb = qdisc.Perturb
opt.TcSfqQopt.Limit = qdisc.Limit
opt.TcSfqQopt.Divisor = qdisc.Divisor
@@ -683,7 +683,7 @@ func parseSfqData(qdisc Qdisc, value []byte) error {
sfq := qdisc.(*Sfq)
opt := nl.DeserializeTcSfqQoptV1(value)
sfq.Quantum = opt.TcSfqQopt.Quantum
sfq.Perturb = uint8(opt.TcSfqQopt.Perturb)
sfq.Perturb = opt.TcSfqQopt.Perturb
sfq.Limit = opt.TcSfqQopt.Limit
sfq.Divisor = opt.TcSfqQopt.Divisor

View File

@@ -18,6 +18,7 @@ type RdmaLinkAttrs struct {
FirmwareVersion string
NodeGuid string
SysImageGuid string
NumPorts uint32
}
// Link represents a rdma device from netlink.
@@ -69,6 +70,11 @@ func executeOneGetRdmaLink(data []byte) (*RdmaLink, error) {
r := bytes.NewReader(value)
binary.Read(r, nl.NativeEndian(), &sysGuid)
link.Attrs.SysImageGuid = uint64ToGuidString(sysGuid)
case nl.RDMA_NLDEV_ATTR_PORT_INDEX:
var availablePort uint32
r := bytes.NewReader(value)
binary.Read(r, nl.NativeEndian(), &availablePort)
link.Attrs.NumPorts = availablePort
}
if (len % 4) != 0 {
// Skip pad bytes
@@ -345,3 +351,212 @@ func (h *Handle) RdmaLinkAdd(linkName string, linkType string, netdev string) er
_, err := req.Execute(unix.NETLINK_RDMA, 0)
return err
}
// RdmaResource represents a rdma device resource tracking summaries
type RdmaResource struct {
Index uint32
Name string
RdmaResourceSummaryEntries map[string]uint64
}
// RdmaResourceList list rdma resource tracking information
// Returns all rdma devices resource tracking summary on success or returns error
// otherwise.
// Equivalent to: `rdma resource'
func RdmaResourceList() ([]*RdmaResource, error) {
return pkgHandle.RdmaResourceList()
}
// RdmaResourceList list rdma resource tracking information
// Returns all rdma devices resource tracking summary on success or returns error
// otherwise.
// Equivalent to: `rdma resource'
func (h *Handle) RdmaResourceList() ([]*RdmaResource, error) {
proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_RES_GET)
req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
if err != nil {
return nil, err
}
if len(msgs) == 0 {
return nil, fmt.Errorf("No valid response from kernel")
}
var rdmaResources []*RdmaResource
for _, msg := range msgs {
res, err := executeOneGetRdmaResourceList(msg)
if err != nil {
return nil, err
}
rdmaResources = append(rdmaResources, res)
}
return rdmaResources, nil
}
func parseRdmaCounters(counterType uint16, data []byte) (map[string]uint64, error) {
var counterKeyType, counterValueType uint16
switch counterType {
case nl.RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY:
counterKeyType = nl.RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME
counterValueType = nl.RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR
case nl.RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY:
counterKeyType = nl.RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME
counterValueType = nl.RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE
default:
return nil, fmt.Errorf("Invalid counter type: %d", counterType)
}
counters := make(map[string]uint64)
reader := bytes.NewReader(data)
for reader.Len() >= 4 {
_, attrType, _, value := parseNfAttrTLV(reader)
if attrType != counterType {
return nil, fmt.Errorf("Invalid resource summary entry type; %d", attrType)
}
summaryReader := bytes.NewReader(value)
for summaryReader.Len() >= 4 {
_, attrType, len, value := parseNfAttrTLV(summaryReader)
if attrType != counterKeyType {
return nil, fmt.Errorf("Invalid resource summary entry name type; %d", attrType)
}
name := string(value[0 : len-1])
// Skip pad bytes
if (len % 4) != 0 {
summaryReader.Seek(int64(4-(len%4)), seekCurrent)
}
_, attrType, len, value = parseNfAttrTLV(summaryReader)
if attrType != counterValueType {
return nil, fmt.Errorf("Invalid resource summary entry value type; %d", attrType)
}
counters[name] = native.Uint64(value)
}
}
return counters, nil
}
func executeOneGetRdmaResourceList(data []byte) (*RdmaResource, error) {
var res RdmaResource
reader := bytes.NewReader(data)
for reader.Len() >= 4 {
_, attrType, len, value := parseNfAttrTLV(reader)
switch attrType {
case nl.RDMA_NLDEV_ATTR_DEV_INDEX:
var Index uint32
r := bytes.NewReader(value)
binary.Read(r, nl.NativeEndian(), &Index)
res.Index = Index
case nl.RDMA_NLDEV_ATTR_DEV_NAME:
res.Name = string(value[0 : len-1])
case nl.RDMA_NLDEV_ATTR_RES_SUMMARY:
var err error
res.RdmaResourceSummaryEntries, err = parseRdmaCounters(nl.RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY, value)
if err != nil {
return nil, err
}
}
if (len % 4) != 0 {
// Skip pad bytes
reader.Seek(int64(4-(len%4)), seekCurrent)
}
}
return &res, nil
}
// RdmaPortStatistic represents a rdma port statistic counter
type RdmaPortStatistic struct {
PortIndex uint32
Statistics map[string]uint64
}
// RdmaDeviceStatistic represents a rdma device statistic counter
type RdmaDeviceStatistic struct {
RdmaPortStatistics []*RdmaPortStatistic
}
// RdmaStatistic get rdma device statistic counters
// Returns rdma device statistic counters on success or returns error
// otherwise.
// Equivalent to: `rdma statistic show link [DEV]'
func RdmaStatistic(link *RdmaLink) (*RdmaDeviceStatistic, error) {
return pkgHandle.RdmaStatistic(link)
}
// RdmaStatistic get rdma device statistic counters
// Returns rdma device statistic counters on success or returns error
// otherwise.
// Equivalent to: `rdma statistic show link [DEV]'
func (h *Handle) RdmaStatistic(link *RdmaLink) (*RdmaDeviceStatistic, error) {
rdmaLinkStatistic := make([]*RdmaPortStatistic, 0)
for portIndex := uint32(1); portIndex <= link.Attrs.NumPorts; portIndex++ {
portStatistic, err := h.RdmaPortStatisticList(link, portIndex)
if err != nil {
return nil, err
}
rdmaLinkStatistic = append(rdmaLinkStatistic, portStatistic)
}
return &RdmaDeviceStatistic{RdmaPortStatistics: rdmaLinkStatistic}, nil
}
// RdmaPortStatisticList get rdma device port statistic counters
// Returns rdma device port statistic counters on success or returns error
// otherwise.
// Equivalent to: `rdma statistic show link [DEV/PORT]'
func RdmaPortStatisticList(link *RdmaLink, port uint32) (*RdmaPortStatistic, error) {
return pkgHandle.RdmaPortStatisticList(link, port)
}
// RdmaPortStatisticList get rdma device port statistic counters
// Returns rdma device port statistic counters on success or returns error
// otherwise.
// Equivalent to: `rdma statistic show link [DEV/PORT]'
func (h *Handle) RdmaPortStatisticList(link *RdmaLink, port uint32) (*RdmaPortStatistic, error) {
proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_STAT_GET)
req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_REQUEST)
b := make([]byte, 4)
native.PutUint32(b, link.Attrs.Index)
data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b)
req.AddData(data)
b = make([]byte, 4)
native.PutUint32(b, port)
data = nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_PORT_INDEX, b)
req.AddData(data)
msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
if err != nil {
return nil, err
}
if len(msgs) != 1 {
return nil, fmt.Errorf("No valid response from kernel")
}
return executeOneGetRdmaPortStatistics(msgs[0])
}
func executeOneGetRdmaPortStatistics(data []byte) (*RdmaPortStatistic, error) {
var stat RdmaPortStatistic
reader := bytes.NewReader(data)
for reader.Len() >= 4 {
_, attrType, len, value := parseNfAttrTLV(reader)
switch attrType {
case nl.RDMA_NLDEV_ATTR_PORT_INDEX:
var Index uint32
r := bytes.NewReader(value)
binary.Read(r, nl.NativeEndian(), &Index)
stat.PortIndex = Index
case nl.RDMA_NLDEV_ATTR_STAT_HWCOUNTERS:
var err error
stat.Statistics, err = parseRdmaCounters(nl.RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY, value)
if err != nil {
return nil, err
}
}
if (len % 4) != 0 {
// Skip pad bytes
reader.Seek(int64(4-(len%4)), seekCurrent)
}
}
return &stat, nil
}

View File

@@ -45,7 +45,7 @@ type Encap interface {
Equal(Encap) bool
}
//Protocol describe what was the originator of the route
// Protocol describe what was the originator of the route
type RouteProtocol int
// Route represents a netlink route.
@@ -70,6 +70,7 @@ type Route struct {
Via Destination
Realm int
MTU int
MTULock bool
Window int
Rtt int
RttVar int
@@ -81,6 +82,7 @@ type Route struct {
InitCwnd int
Features int
RtoMin int
RtoMinLock bool
InitRwnd int
QuickACK int
Congctl string

View File

@@ -270,6 +270,7 @@ type SEG6LocalEncap struct {
Action int
Segments []net.IP // from SRH in seg6_local_lwt
Table int // table id for End.T and End.DT6
VrfTable int // vrftable id for END.DT4 and END.DT6
InAddr net.IP
In6Addr net.IP
Iif int
@@ -305,6 +306,9 @@ func (e *SEG6LocalEncap) Decode(buf []byte) error {
case nl.SEG6_LOCAL_TABLE:
e.Table = int(native.Uint32(attr.Value[0:4]))
e.Flags[nl.SEG6_LOCAL_TABLE] = true
case nl.SEG6_LOCAL_VRFTABLE:
e.VrfTable = int(native.Uint32(attr.Value[0:4]))
e.Flags[nl.SEG6_LOCAL_VRFTABLE] = true
case nl.SEG6_LOCAL_NH4:
e.InAddr = net.IP(attr.Value[0:4])
e.Flags[nl.SEG6_LOCAL_NH4] = true
@@ -361,6 +365,15 @@ func (e *SEG6LocalEncap) Encode() ([]byte, error) {
native.PutUint32(attr[4:], uint32(e.Table))
res = append(res, attr...)
}
if e.Flags[nl.SEG6_LOCAL_VRFTABLE] {
attr := make([]byte, 8)
native.PutUint16(attr, 8)
native.PutUint16(attr[2:], nl.SEG6_LOCAL_VRFTABLE)
native.PutUint32(attr[4:], uint32(e.VrfTable))
res = append(res, attr...)
}
if e.Flags[nl.SEG6_LOCAL_NH4] {
attr := make([]byte, 4)
native.PutUint16(attr, 8)
@@ -413,6 +426,11 @@ func (e *SEG6LocalEncap) String() string {
if e.Flags[nl.SEG6_LOCAL_TABLE] {
strs = append(strs, fmt.Sprintf("table %d", e.Table))
}
if e.Flags[nl.SEG6_LOCAL_VRFTABLE] {
strs = append(strs, fmt.Sprintf("vrftable %d", e.VrfTable))
}
if e.Flags[nl.SEG6_LOCAL_NH4] {
strs = append(strs, fmt.Sprintf("nh4 %s", e.InAddr))
}
@@ -477,7 +495,7 @@ func (e *SEG6LocalEncap) Equal(x Encap) bool {
if !e.InAddr.Equal(o.InAddr) || !e.In6Addr.Equal(o.In6Addr) {
return false
}
if e.Action != o.Action || e.Table != o.Table || e.Iif != o.Iif || e.Oif != o.Oif || e.bpf != o.bpf {
if e.Action != o.Action || e.Table != o.Table || e.Iif != o.Iif || e.Oif != o.Oif || e.bpf != o.bpf || e.VrfTable != o.VrfTable {
return false
}
return true
@@ -1072,6 +1090,10 @@ func (h *Handle) prepareRouteReq(route *Route, req *nl.NetlinkRequest, msg *nl.R
if route.MTU > 0 {
b := nl.Uint32Attr(uint32(route.MTU))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_MTU, b))
if route.MTULock {
b := nl.Uint32Attr(uint32(1 << unix.RTAX_MTU))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_LOCK, b))
}
}
if route.Window > 0 {
b := nl.Uint32Attr(uint32(route.Window))
@@ -1116,6 +1138,10 @@ func (h *Handle) prepareRouteReq(route *Route, req *nl.NetlinkRequest, msg *nl.R
if route.RtoMin > 0 {
b := nl.Uint32Attr(uint32(route.RtoMin))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_RTO_MIN, b))
if route.RtoMinLock {
b := nl.Uint32Attr(uint32(1 << unix.RTAX_RTO_MIN))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_LOCK, b))
}
}
if route.InitRwnd > 0 {
b := nl.Uint32Attr(uint32(route.InitRwnd))
@@ -1440,6 +1466,9 @@ func deserializeRoute(m []byte) (Route, error) {
switch metric.Attr.Type {
case unix.RTAX_MTU:
route.MTU = int(native.Uint32(metric.Value[0:4]))
case unix.RTAX_LOCK:
route.MTULock = native.Uint32(metric.Value[0:4]) == uint32(1<<unix.RTAX_MTU)
route.RtoMinLock = native.Uint32(metric.Value[0:4]) == uint32(1<<unix.RTAX_RTO_MIN)
case unix.RTAX_WINDOW:
route.Window = int(native.Uint32(metric.Value[0:4]))
case unix.RTAX_RTT:
@@ -1533,6 +1562,7 @@ type RouteGetOptions struct {
Iif string
IifIndex int
Oif string
OifIndex int
VrfName string
SrcAddr net.IP
UID *uint32
@@ -1612,14 +1642,20 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption
req.AddData(nl.NewRtAttr(unix.RTA_IIF, b))
}
oifIndex := uint32(0)
if len(options.Oif) > 0 {
link, err := h.LinkByName(options.Oif)
if err != nil {
return nil, err
}
oifIndex = uint32(link.Attrs().Index)
} else if options.OifIndex > 0 {
oifIndex = uint32(options.OifIndex)
}
if oifIndex > 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Attrs().Index))
native.PutUint32(b, oifIndex)
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
}

View File

@@ -500,7 +500,7 @@ func (h *Handle) UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) {
var attrs []syscall.NetlinkRouteAttr
var err error
if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil {
if attrs, err = nl.ParseRouteAttr(msg[sizeofUnixSocket:]); err != nil {
return false
}

View File

@@ -48,6 +48,14 @@ const (
XFRM_MODE_MAX
)
// SADir is an enum representing an ipsec template direction.
type SADir uint8
const (
XFRM_SA_DIR_IN SADir = iota + 1
XFRM_SA_DIR_OUT
)
func (m Mode) String() string {
switch m {
case XFRM_MODE_TRANSPORT:

View File

@@ -113,7 +113,9 @@ type XfrmState struct {
Statistics XfrmStateStats
Mark *XfrmMark
OutputMark *XfrmMark
SADir SADir
Ifid int
Pcpunum *uint32
Auth *XfrmStateAlgo
Crypt *XfrmStateAlgo
Aead *XfrmStateAlgo
@@ -126,8 +128,8 @@ type XfrmState struct {
}
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: %v, Ifid: %d, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t, DontEncapDSCP: %t, OSeqMayWrap: %t, Replay: %v",
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.DontEncapDSCP, sa.OSeqMayWrap, sa.Replay)
return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, OutputMark: %v, SADir: %d, Ifid: %d, Pcpunum: %d, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t, DontEncapDSCP: %t, OSeqMayWrap: %t, Replay: %v",
sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.OutputMark, sa.SADir, sa.Ifid, *sa.Pcpunum, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN, sa.DontEncapDSCP, sa.OSeqMayWrap, sa.Replay)
}
func (sa XfrmState) Print(stats bool) string {
if !stats {
@@ -333,11 +335,21 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
req.AddData(out)
}
if state.SADir != 0 {
saDir := nl.NewRtAttr(nl.XFRMA_SA_DIR, nl.Uint8Attr(uint8(state.SADir)))
req.AddData(saDir)
}
if state.Ifid != 0 {
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
req.AddData(ifId)
}
if state.Pcpunum != nil {
pcpuNum := nl.NewRtAttr(nl.XFRMA_SA_PCPU, nl.Uint32Attr(uint32(*state.Pcpunum)))
req.AddData(pcpuNum)
}
_, err := req.Execute(unix.NETLINK_XFRM, 0)
return err
}
@@ -459,6 +471,11 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState
req.AddData(ifId)
}
if state.Pcpunum != nil {
pcpuNum := nl.NewRtAttr(nl.XFRMA_SA_PCPU, nl.Uint32Attr(uint32(*state.Pcpunum)))
req.AddData(pcpuNum)
}
resType := nl.XFRM_MSG_NEWSA
if nlProto == nl.XFRM_MSG_DELSA {
resType = 0
@@ -581,8 +598,13 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
if state.OutputMark.Mask == 0xffffffff {
state.OutputMark.Mask = 0
}
case nl.XFRMA_SA_DIR:
state.SADir = SADir(attr.Value[0])
case nl.XFRMA_IF_ID:
state.Ifid = int(native.Uint32(attr.Value))
case nl.XFRMA_SA_PCPU:
pcpuNum := native.Uint32(attr.Value)
state.Pcpunum = &pcpuNum
case nl.XFRMA_REPLAY_VAL:
if state.Replay == nil {
state.Replay = new(XfrmReplayState)

View File

@@ -1,2 +1,26 @@
linters:
enable:
- errcheck
- errorlint
- gocritic
- gosec
- gosimple
- govet
- gci
- misspell
- nonamedreturns
- staticcheck
- unconvert
- unparam
- unused
- whitespace
linters-settings:
gci:
sections:
- standard
- default
- prefix(github.com/vishvananda)
run:
timeout: 5m

9
vendor/github.com/vishvananda/netns/.yamllint.yml generated vendored Normal file
View File

@@ -0,0 +1,9 @@
---
extends: default
rules:
document-start: disable
line-length: disable
truthy:
ignore: |
.github/workflows/*.yml

View File

@@ -26,19 +26,19 @@ const bindMountPath = "/run/netns" /* Bind mount path for named netns */
// Setns sets namespace using golang.org/x/sys/unix.Setns.
//
// Deprecated: Use golang.org/x/sys/unix.Setns instead.
func Setns(ns NsHandle, nstype int) (err error) {
func Setns(ns NsHandle, nstype int) error {
return unix.Setns(int(ns), nstype)
}
// Set sets the current network namespace to the namespace represented
// by NsHandle.
func Set(ns NsHandle) (err error) {
func Set(ns NsHandle) error {
return unix.Setns(int(ns), unix.CLONE_NEWNET)
}
// New creates a new network namespace, sets it as current and returns
// a handle to it.
func New() (ns NsHandle, err error) {
func New() (NsHandle, error) {
if err := unix.Unshare(unix.CLONE_NEWNET); err != nil {
return -1, err
}
@@ -49,7 +49,7 @@ func New() (ns NsHandle, err error) {
// and returns a handle to it
func NewNamed(name string) (NsHandle, error) {
if _, err := os.Stat(bindMountPath); os.IsNotExist(err) {
err = os.MkdirAll(bindMountPath, 0755)
err = os.MkdirAll(bindMountPath, 0o755)
if err != nil {
return None(), err
}
@@ -62,7 +62,7 @@ func NewNamed(name string) (NsHandle, error) {
namedPath := path.Join(bindMountPath, name)
f, err := os.OpenFile(namedPath, os.O_CREATE|os.O_EXCL, 0444)
f, err := os.OpenFile(namedPath, os.O_CREATE|os.O_EXCL, 0o444)
if err != nil {
newNs.Close()
return None(), err
@@ -217,11 +217,12 @@ func getPidForContainer(id string) (int, error) {
id += "*"
var pidFile string
if cgroupVer == 1 {
switch cgroupVer {
case 1:
pidFile = "tasks"
} else if cgroupVer == 2 {
case 2:
pidFile = "cgroup.procs"
} else {
default:
return -1, fmt.Errorf("Invalid cgroup version '%d'", cgroupVer)
}
@@ -247,6 +248,10 @@ func getPidForContainer(id string) (int, error) {
filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile),
// Same as above but for Guaranteed QoS
filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", pidFile),
// Support for nerdctl
filepath.Join(cgroupRoot, "system.slice", "nerdctl-"+id+".scope", pidFile),
// Support for finch
filepath.Join(cgroupRoot, "..", "systemd", "finch", id, pidFile),
}
var filename string
@@ -276,7 +281,7 @@ func getPidForContainer(id string) (int, error) {
pid, err = strconv.Atoi(result[0])
if err != nil {
return pid, fmt.Errorf("Invalid pid '%s': %s", result[0], err)
return pid, fmt.Errorf("Invalid pid '%s': %w", result[0], err)
}
return pid, nil

View File

@@ -3,27 +3,23 @@
package netns
import (
"errors"
)
import "errors"
var (
ErrNotImplemented = errors.New("not implemented")
)
var ErrNotImplemented = errors.New("not implemented")
// Setns sets namespace using golang.org/x/sys/unix.Setns on Linux. It
// is not implemented on other platforms.
//
// Deprecated: Use golang.org/x/sys/unix.Setns instead.
func Setns(ns NsHandle, nstype int) (err error) {
func Setns(ns NsHandle, nstype int) error {
return ErrNotImplemented
}
func Set(ns NsHandle) (err error) {
func Set(ns NsHandle) error {
return ErrNotImplemented
}
func New() (ns NsHandle, err error) {
func New() (NsHandle, error) {
return -1, ErrNotImplemented
}
@@ -51,7 +47,7 @@ func GetFromPid(pid int) (NsHandle, error) {
return -1, ErrNotImplemented
}
func GetFromThread(pid, tid int) (NsHandle, error) {
func GetFromThread(pid int, tid int) (NsHandle, error) {
return -1, ErrNotImplemented
}

4
vendor/modules.txt vendored
View File

@@ -557,11 +557,11 @@ github.com/stretchr/testify/require
# github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75
## explicit; go 1.15
github.com/tmc/grpc-websocket-proxy/wsproxy
# github.com/vishvananda/netlink v1.3.1-0.20250206174618-62fb240731fa
# github.com/vishvananda/netlink v1.3.1
## explicit; go 1.12
github.com/vishvananda/netlink
github.com/vishvananda/netlink/nl
# github.com/vishvananda/netns v0.0.4
# github.com/vishvananda/netns v0.0.5
## explicit; go 1.17
github.com/vishvananda/netns
# github.com/x448/float16 v0.8.4