fix(deps): update module github.com/vishvananda/netlink to v1.3.1

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This commit is contained in:
renovate[bot] 2025-05-09 21:52:54 +00:00 committed by GitHub
parent 811aabd3b0
commit a5748206d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 773 additions and 100 deletions

2
go.mod
View File

@ -66,7 +66,7 @@ require (
github.com/spf13/pflag v1.0.6 github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/vbauerster/mpb/v8 v8.10.0 github.com/vbauerster/mpb/v8 v8.10.0
github.com/vishvananda/netlink v1.3.1-0.20250425193846-9d88d8385bf9 github.com/vishvananda/netlink v1.3.1
go.etcd.io/bbolt v1.4.0 go.etcd.io/bbolt v1.4.0
golang.org/x/crypto v0.38.0 golang.org/x/crypto v0.38.0
golang.org/x/net v0.40.0 golang.org/x/net v0.40.0

4
go.sum
View File

@ -482,8 +482,8 @@ github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnn
github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
github.com/vbauerster/mpb/v8 v8.10.0 h1:5ZYEWM4ovaZGAibjzW4PlQNb5k+JpzMqVwgNyk+K0M8= github.com/vbauerster/mpb/v8 v8.10.0 h1:5ZYEWM4ovaZGAibjzW4PlQNb5k+JpzMqVwgNyk+K0M8=
github.com/vbauerster/mpb/v8 v8.10.0/go.mod h1:DYPFebxSahB+f7tuEUGauLQ7w8ij3wMr4clsVuJCV4I= github.com/vbauerster/mpb/v8 v8.10.0/go.mod h1:DYPFebxSahB+f7tuEUGauLQ7w8ij3wMr4clsVuJCV4I=
github.com/vishvananda/netlink v1.3.1-0.20250425193846-9d88d8385bf9 h1:ZEjCI2kamoTYIx348/Nfco4c4NPvpq972DM2HMgnBgI= github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
github.com/vishvananda/netlink v1.3.1-0.20250425193846-9d88d8385bf9/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= 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 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=

View File

@ -3,11 +3,102 @@ package netlink
import ( import (
"errors" "errors"
"fmt" "fmt"
"syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix" "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. // BridgeVlanList gets a map of device id to bridge vlan infos.
// Equivalent to: `bridge vlan show` // Equivalent to: `bridge vlan show`
// //
@ -61,6 +152,38 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
return ret, executeErr 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 // BridgeVlanAdd adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]` // 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 { 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 // BridgeVlanAdd adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]` // 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 { 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 // 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 // BridgeVlanAddRange adds a new vlan filter entry
// Equivalent to: `bridge vlan add dev DEV vid VID-VIDEND [ pvid ] [ untagged ] [ self ] [ master ]` // 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 { 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 // 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 // BridgeVlanDel adds a new vlan filter entry
// Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]` // 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 { 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 // 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 // BridgeVlanDelRange adds a new vlan filter entry
// Equivalent to: `bridge vlan del dev DEV vid VID-VIDEND [ pvid ] [ untagged ] [ self ] [ master ]` // 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 { 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() base := link.Attrs()
h.ensureIndex(base) h.ensureIndex(base)
req := h.newNetlinkRequest(cmd, unix.NLM_F_ACK) 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 { if flags > 0 {
br.AddRtAttr(nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags)) 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 { if tunid != 0 {
vlanEndInfo := &nl.BridgeVlanInfo{Vid: vidEnd} if tunidEnd != 0 {
vlanEndInfo.Flags = vlanInfo.Flags 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 tiEnd := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize()) 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 if vidEnd != 0 {
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanEndInfo.Serialize()) vlanEndInfo := &nl.BridgeVlanInfo{Vid: vidEnd}
} else { vlanEndInfo.Flags = vlanInfo.Flags
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
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) req.AddData(br)

View File

@ -54,25 +54,30 @@ func (filter *U32) Type() string {
type Flower struct { type Flower struct {
FilterAttrs FilterAttrs
DestIP net.IP ClassId uint32
DestIPMask net.IPMask DestIP net.IP
SrcIP net.IP DestIPMask net.IPMask
SrcIPMask net.IPMask SrcIP net.IP
EthType uint16 SrcIPMask net.IPMask
EncDestIP net.IP EthType uint16
EncDestIPMask net.IPMask EncDestIP net.IP
EncSrcIP net.IP EncDestIPMask net.IPMask
EncSrcIPMask net.IPMask EncSrcIP net.IP
EncDestPort uint16 EncSrcIPMask net.IPMask
EncKeyId uint32 EncDestPort uint16
SrcMac net.HardwareAddr EncKeyId uint32
DestMac net.HardwareAddr SrcMac net.HardwareAddr
VlanId uint16 DestMac net.HardwareAddr
SkipHw bool VlanId uint16
SkipSw bool SkipHw bool
IPProto *nl.IPProto SkipSw bool
DestPort uint16 IPProto *nl.IPProto
SrcPort uint16 DestPort uint16
SrcPort uint16
SrcPortRangeMin uint16
SrcPortRangeMax uint16
DstPortRangeMin uint16
DstPortRangeMax uint16
Actions []Action 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 var flags uint32 = 0
if filter.SkipHw { if filter.SkipHw {
@ -247,6 +265,16 @@ func (filter *Flower) decode(data []syscall.NetlinkRouteAttr) error {
if skipHw != 0 { if skipHw != 0 {
filter.SkipHw = true 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 return nil

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_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)))
cadtFlags := optionsToBitflag(options)
revision := options.Revision revision := options.Revision
if revision == 0 { if revision == 0 {
revision = getIpsetDefaultWithTypeName(typename) revision = getIpsetDefaultRevision(typename, cadtFlags)
} }
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(revision))) 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}) 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 { if cadtFlags != 0 {
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER, Value: cadtFlags}) 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 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 { switch typename {
case "hash:ip,port", case "hash:ip,port",
"hash:ip,port,ip", "hash:ip,port,ip":
"hash:ip,port,net", // 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": "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 return 1
} }
// can't map the correct revision for this type.
return 0 return 0
} }
@ -579,3 +644,19 @@ func parseIPSetEntry(data []byte) (entry IPSetEntry) {
} }
return 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() // Vlan links have ParentIndex set in their Attrs()
type Vlan struct { type Vlan struct {
LinkAttrs LinkAttrs
VlanId int VlanId int
VlanProtocol VlanProtocol 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 { func (vlan *Vlan) Attrs() *LinkAttrs {
@ -426,6 +433,17 @@ type Veth struct {
PeerName string // veth on create only PeerName string // veth on create only
PeerHardwareAddr net.HardwareAddr PeerHardwareAddr net.HardwareAddr
PeerNamespace interface{} 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 { func (veth *Veth) Attrs() *LinkAttrs {

View File

@ -1683,6 +1683,73 @@ func (h *Handle) linkModify(link Link, flags int) error {
native.PutUint16(b, uint16(link.VlanId)) native.PutUint16(b, uint16(link.VlanId))
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_VLAN_ID, b) 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 { if link.VlanProtocol != VLAN_PROTOCOL_UNKNOWN {
data.AddRtAttr(nl.IFLA_VLAN_PROTOCOL, htons(uint16(link.VlanProtocol))) 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) peer := data.AddRtAttr(nl.VETH_INFO_PEER, nil)
nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC) nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC)
peer.AddRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName)) 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))) 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))) 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))) 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))) peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
} }
if link.PeerHardwareAddr != nil { 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) 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 { func LinkSetRootBlock(link Link, mode bool) error {
return pkgHandle.LinkSetRootBlock(link, mode) return pkgHandle.LinkSetRootBlock(link, mode)
} }
@ -2784,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) { func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
vlan := link.(*Vlan) vlan := link.(*Vlan)
for _, datum := range data { for _, datum := range data {
switch datum.Attr.Type { switch datum.Attr.Type {
case nl.IFLA_VLAN_ID: case nl.IFLA_VLAN_ID:
vlan.VlanId = int(native.Uint16(datum.Value[0:2])) 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: case nl.IFLA_VLAN_PROTOCOL:
vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2]))) vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2])))
} }

View File

@ -26,6 +26,14 @@ const (
IFLA_BRIDGE_FLAGS = iota IFLA_BRIDGE_FLAGS = iota
IFLA_BRIDGE_MODE IFLA_BRIDGE_MODE
IFLA_BRIDGE_VLAN_INFO 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 ( const (
@ -41,6 +49,11 @@ const (
// __u16 vid; // __u16 vid;
// }; // };
type TunnelInfo struct {
TunId uint32
Vid uint16
}
type BridgeVlanInfo struct { type BridgeVlanInfo struct {
Flags uint16 Flags uint16
Vid uint16 Vid uint16

View File

@ -31,6 +31,20 @@ const (
IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL 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 ( const (
IFLA_NETKIT_UNSPEC = iota IFLA_NETKIT_UNSPEC = iota
IFLA_NETKIT_PEER_INFO IFLA_NETKIT_PEER_INFO

View File

@ -9,31 +9,41 @@ const (
) )
const ( const (
RDMA_NLDEV_CMD_GET = 1 RDMA_NLDEV_CMD_GET = 1
RDMA_NLDEV_CMD_SET = 2 RDMA_NLDEV_CMD_SET = 2
RDMA_NLDEV_CMD_NEWLINK = 3 RDMA_NLDEV_CMD_NEWLINK = 3
RDMA_NLDEV_CMD_DELLINK = 4 RDMA_NLDEV_CMD_DELLINK = 4
RDMA_NLDEV_CMD_SYS_GET = 6 RDMA_NLDEV_CMD_SYS_GET = 6
RDMA_NLDEV_CMD_SYS_SET = 7 RDMA_NLDEV_CMD_SYS_SET = 7
RDMA_NLDEV_CMD_RES_GET = 9
RDMA_NLDEV_CMD_STAT_GET = 17
) )
const ( const (
RDMA_NLDEV_ATTR_DEV_INDEX = 1 RDMA_NLDEV_ATTR_DEV_INDEX = 1
RDMA_NLDEV_ATTR_DEV_NAME = 2 RDMA_NLDEV_ATTR_DEV_NAME = 2
RDMA_NLDEV_ATTR_PORT_INDEX = 3 RDMA_NLDEV_ATTR_PORT_INDEX = 3
RDMA_NLDEV_ATTR_CAP_FLAGS = 4 RDMA_NLDEV_ATTR_CAP_FLAGS = 4
RDMA_NLDEV_ATTR_FW_VERSION = 5 RDMA_NLDEV_ATTR_FW_VERSION = 5
RDMA_NLDEV_ATTR_NODE_GUID = 6 RDMA_NLDEV_ATTR_NODE_GUID = 6
RDMA_NLDEV_ATTR_SYS_IMAGE_GUID = 7 RDMA_NLDEV_ATTR_SYS_IMAGE_GUID = 7
RDMA_NLDEV_ATTR_SUBNET_PREFIX = 8 RDMA_NLDEV_ATTR_SUBNET_PREFIX = 8
RDMA_NLDEV_ATTR_LID = 9 RDMA_NLDEV_ATTR_LID = 9
RDMA_NLDEV_ATTR_SM_LID = 10 RDMA_NLDEV_ATTR_SM_LID = 10
RDMA_NLDEV_ATTR_LMC = 11 RDMA_NLDEV_ATTR_LMC = 11
RDMA_NLDEV_ATTR_PORT_STATE = 12 RDMA_NLDEV_ATTR_PORT_STATE = 12
RDMA_NLDEV_ATTR_PORT_PHYS_STATE = 13 RDMA_NLDEV_ATTR_PORT_PHYS_STATE = 13
RDMA_NLDEV_ATTR_DEV_NODE_TYPE = 14 RDMA_NLDEV_ATTR_DEV_NODE_TYPE = 14
RDMA_NLDEV_ATTR_NDEV_NAME = 51 RDMA_NLDEV_ATTR_RES_SUMMARY = 15
RDMA_NLDEV_ATTR_LINK_TYPE = 65 RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY = 16
RDMA_NLDEV_SYS_ATTR_NETNS_MODE = 66 RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME = 17
RDMA_NLDEV_NET_NS_FD = 68 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

@ -1123,6 +1123,13 @@ const (
TCA_FLOWER_KEY_ENC_OPTS TCA_FLOWER_KEY_ENC_OPTS
TCA_FLOWER_KEY_ENC_OPTS_MASK 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 __TCA_FLOWER_MAX
) )
@ -1138,11 +1145,11 @@ const TCA_CLS_FLAGS_SKIP_SW = 1 << 1 /* don't use filter in SW */
// }; // };
type TcSfqQopt struct { type TcSfqQopt struct {
Quantum uint8 Quantum uint32
Perturb int32 Perturb int32
Limit uint32 Limit uint32
Divisor uint8 Divisor uint32
Flows uint8 Flows uint32
} }
func (x *TcSfqQopt) Len() int { func (x *TcSfqQopt) Len() int {
@ -1580,7 +1587,7 @@ func (p *TcPedit) SetIPv6Dst(ip6 net.IP) {
} }
func (p *TcPedit) SetIPv4Src(ip net.IP) { func (p *TcPedit) SetIPv4Src(ip net.IP) {
u32 := NativeEndian().Uint32(ip[:4]) u32 := NativeEndian().Uint32(ip.To4())
tKey := TcPeditKey{} tKey := TcPeditKey{}
tKeyEx := TcPeditKeyEx{} tKeyEx := TcPeditKeyEx{}
@ -1596,7 +1603,7 @@ func (p *TcPedit) SetIPv4Src(ip net.IP) {
} }
func (p *TcPedit) SetIPv4Dst(ip net.IP) { func (p *TcPedit) SetIPv4Dst(ip net.IP) {
u32 := NativeEndian().Uint32(ip[:4]) u32 := NativeEndian().Uint32(ip.To4())
tKey := TcPeditKey{} tKey := TcPeditKey{}
tKeyEx := TcPeditKeyEx{} tKeyEx := TcPeditKeyEx{}

View File

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

View File

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

View File

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

View File

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

View File

@ -18,6 +18,7 @@ type RdmaLinkAttrs struct {
FirmwareVersion string FirmwareVersion string
NodeGuid string NodeGuid string
SysImageGuid string SysImageGuid string
NumPorts uint32
} }
// Link represents a rdma device from netlink. // Link represents a rdma device from netlink.
@ -69,6 +70,11 @@ func executeOneGetRdmaLink(data []byte) (*RdmaLink, error) {
r := bytes.NewReader(value) r := bytes.NewReader(value)
binary.Read(r, nl.NativeEndian(), &sysGuid) binary.Read(r, nl.NativeEndian(), &sysGuid)
link.Attrs.SysImageGuid = uint64ToGuidString(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 { if (len % 4) != 0 {
// Skip pad bytes // 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) _, err := req.Execute(unix.NETLINK_RDMA, 0)
return err 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
}

2
vendor/modules.txt vendored
View File

@ -996,7 +996,7 @@ github.com/vbauerster/mpb/v8
github.com/vbauerster/mpb/v8/cwriter github.com/vbauerster/mpb/v8/cwriter
github.com/vbauerster/mpb/v8/decor github.com/vbauerster/mpb/v8/decor
github.com/vbauerster/mpb/v8/internal github.com/vbauerster/mpb/v8/internal
# github.com/vishvananda/netlink v1.3.1-0.20250425193846-9d88d8385bf9 # github.com/vishvananda/netlink v1.3.1
## explicit; go 1.12 ## explicit; go 1.12
github.com/vishvananda/netlink github.com/vishvananda/netlink
github.com/vishvananda/netlink/nl github.com/vishvananda/netlink/nl