Merge pull request #2769 from sameo/topic/agent-route

Pass the host route IP family to the guest
This commit is contained in:
Eric Ernst 2021-10-05 07:20:33 -07:00 committed by GitHub
commit 2bc7561561
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 2544 additions and 379 deletions

View File

@ -46,6 +46,7 @@ message Route {
string device = 3; string device = 3;
string source = 4; string source = 4;
uint32 scope = 5; uint32 scope = 5;
IPFamily family = 6;
} }
message ARPNeighbor { message ARPNeighbor {

View File

@ -312,7 +312,6 @@ impl Handle {
for route in list { for route in list {
let link = self.find_link(LinkFilter::Name(&route.device)).await?; let link = self.find_link(LinkFilter::Name(&route.device)).await?;
let is_v6 = is_ipv6(route.get_gateway()) || is_ipv6(route.get_dest());
const MAIN_TABLE: u8 = packet::constants::RT_TABLE_MAIN; const MAIN_TABLE: u8 = packet::constants::RT_TABLE_MAIN;
const UNICAST: u8 = packet::constants::RTN_UNICAST; const UNICAST: u8 = packet::constants::RTN_UNICAST;
@ -334,7 +333,7 @@ impl Handle {
// `rtnetlink` offers a separate request builders for different IP versions (IP v4 and v6). // `rtnetlink` offers a separate request builders for different IP versions (IP v4 and v6).
// This if branch is a bit clumsy because it does almost the same. // This if branch is a bit clumsy because it does almost the same.
if is_v6 { if route.get_family() == IPFamily::v6 {
let dest_addr = if !route.dest.is_empty() { let dest_addr = if !route.dest.is_empty() {
Ipv6Network::from_str(&route.dest)? Ipv6Network::from_str(&route.dest)?
} else { } else {
@ -594,10 +593,6 @@ fn format_address(data: &[u8]) -> Result<String> {
} }
} }
fn is_ipv6(str: &str) -> bool {
Ipv6Addr::from_str(str).is_ok()
}
fn parse_mac_address(addr: &str) -> Result<[u8; 6]> { fn parse_mac_address(addr: &str) -> Result<[u8; 6]> {
let mut split = addr.splitn(6, ':'); let mut split = addr.splitn(6, ':');
@ -932,16 +927,6 @@ mod tests {
assert_eq!(bytes, [0xAB, 0x0C, 0xDE, 0x12, 0x34, 0x56]); assert_eq!(bytes, [0xAB, 0x0C, 0xDE, 0x12, 0x34, 0x56]);
} }
#[test]
fn check_ipv6() {
assert!(is_ipv6("::1"));
assert!(is_ipv6("2001:0:3238:DFE1:63::FEFB"));
assert!(!is_ipv6(""));
assert!(!is_ipv6("127.0.0.1"));
assert!(!is_ipv6("10.10.10.10"));
}
fn clean_env_for_test_add_one_arp_neighbor(dummy_name: &str, ip: &str) { fn clean_env_for_test_add_one_arp_neighbor(dummy_name: &str, ip: &str) {
// ip link delete dummy // ip link delete dummy
Command::new("ip") Command::new("ip")

View File

@ -170,7 +170,7 @@ func newNetmon(params netmonParams) (*netmon, error) {
func (n *netmon) cleanup() { func (n *netmon) cleanup() {
os.RemoveAll(n.storagePath) os.RemoveAll(n.storagePath)
n.netHandler.Delete() n.netHandler.Close()
close(n.linkDoneCh) close(n.linkDoneCh)
close(n.rtDoneCh) close(n.rtDoneCh)
} }

View File

@ -348,7 +348,7 @@ func TestScanNetwork(t *testing.T) {
handler, err := netlink.NewHandle(netlinkFamily) handler, err := netlink.NewHandle(netlinkFamily)
assert.Nil(t, err) assert.Nil(t, err)
assert.NotNil(t, handler) assert.NotNil(t, handler)
defer handler.Delete() defer handler.Close()
idx, expected := testCreateDummyNetwork(t, handler) idx, expected := testCreateDummyNetwork(t, handler)
@ -480,7 +480,7 @@ func TestActionsCLI(t *testing.T) {
handler, err := netlink.NewHandle(netlinkFamily) handler, err := netlink.NewHandle(netlinkFamily)
assert.Nil(t, err) assert.Nil(t, err)
assert.NotNil(t, handler) assert.NotNil(t, handler)
defer handler.Delete() defer handler.Close()
n.netHandler = handler n.netHandler = handler
@ -569,7 +569,7 @@ func TestHandleRTMNewLink(t *testing.T) {
handler, err := netlink.NewHandle(netlinkFamily) handler, err := netlink.NewHandle(netlinkFamily)
assert.Nil(t, err) assert.Nil(t, err)
assert.NotNil(t, handler) assert.NotNil(t, handler)
defer handler.Delete() defer handler.Close()
n.netHandler = handler n.netHandler = handler
err = n.handleRTMNewLink(ev) err = n.handleRTMNewLink(ev)
assert.NotNil(t, err) assert.NotNil(t, err)
@ -690,7 +690,7 @@ func TestHandleRouteEvent(t *testing.T) {
handler, err := netlink.NewHandle(netlinkFamily) handler, err := netlink.NewHandle(netlinkFamily)
assert.Nil(t, err) assert.Nil(t, err)
assert.NotNil(t, handler) assert.NotNil(t, handler)
defer handler.Delete() defer handler.Close()
n.netHandler = handler n.netHandler = handler

View File

@ -40,7 +40,7 @@ require (
github.com/smartystreets/goconvey v1.6.4 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.6.1
github.com/urfave/cli v1.22.2 github.com/urfave/cli v1.22.2
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 github.com/vishvananda/netlink v1.1.1-0.20210924202909-187053b97868
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae
go.opentelemetry.io/otel v0.15.0 go.opentelemetry.io/otel v0.15.0
go.opentelemetry.io/otel/exporters/trace/jaeger v0.15.0 go.opentelemetry.io/otel/exporters/trace/jaeger v0.15.0

View File

@ -532,8 +532,9 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 h1:cPXZWzzG0NllBLdjWoD1nDfaqu98YMv+OneaKc8sPOA=
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netlink v1.1.1-0.20210924202909-187053b97868 h1:FFT5/l13iFxg+2dzyoiXZPmMtoclsyBKnUqTEzYpDXw=
github.com/vishvananda/netlink v1.1.1-0.20210924202909-187053b97868/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3Cym0ZtKyq7L16eZUtYKs+BaHDN6mAns=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=

View File

@ -1,6 +1,6 @@
# netlink - netlink library for go # # netlink - netlink library for go #
[![Build Status](https://travis-ci.org/vishvananda/netlink.png?branch=master)](https://travis-ci.org/vishvananda/netlink) [![GoDoc](https://godoc.org/github.com/vishvananda/netlink?status.svg)](https://godoc.org/github.com/vishvananda/netlink) [![Build Status](https://app.travis-ci.com/vishvananda/netlink.svg?branch=master)](https://app.travis-ci.com/github/vishvananda/netlink) [![GoDoc](https://godoc.org/github.com/vishvananda/netlink?status.svg)](https://godoc.org/github.com/vishvananda/netlink)
The netlink package provides a simple netlink library for go. Netlink The netlink package provides a simple netlink library for go. Netlink
is the interface a user-space program in linux uses to communicate with is the interface a user-space program in linux uses to communicate with

View File

@ -268,7 +268,7 @@ func parseAddr(m []byte) (addr Addr, family int, err error) {
// But obviously, as there are IPv6 PtP addresses, too, // But obviously, as there are IPv6 PtP addresses, too,
// IFA_LOCAL should also be handled for IPv6. // IFA_LOCAL should also be handled for IPv6.
if local != nil { if local != nil {
if family == FAMILY_V4 && local.IP.Equal(dst.IP) { if family == FAMILY_V4 && dst != nil && local.IP.Equal(dst.IP) {
addr.IPNet = dst addr.IPNet = dst
} else { } else {
addr.IPNet = local addr.IPNet = local
@ -357,7 +357,8 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
msgs, from, err := s.Receive() msgs, from, err := s.Receive()
if err != nil { if err != nil {
if cberr != nil { if cberr != nil {
cberr(err) cberr(fmt.Errorf("Receive failed: %v",
err))
} }
return return
} }
@ -372,7 +373,6 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
continue continue
} }
if m.Header.Type == unix.NLMSG_ERROR { if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4])) error := int32(native.Uint32(m.Data[0:4]))
if error == 0 { if error == 0 {
continue continue

View File

@ -16,6 +16,30 @@ const (
BPF_PROG_TYPE_SCHED_ACT BPF_PROG_TYPE_SCHED_ACT
BPF_PROG_TYPE_TRACEPOINT BPF_PROG_TYPE_TRACEPOINT
BPF_PROG_TYPE_XDP BPF_PROG_TYPE_XDP
BPF_PROG_TYPE_PERF_EVENT
BPF_PROG_TYPE_CGROUP_SKB
BPF_PROG_TYPE_CGROUP_SOCK
BPF_PROG_TYPE_LWT_IN
BPF_PROG_TYPE_LWT_OUT
BPF_PROG_TYPE_LWT_XMIT
BPF_PROG_TYPE_SOCK_OPS
BPF_PROG_TYPE_SK_SKB
BPF_PROG_TYPE_CGROUP_DEVICE
BPF_PROG_TYPE_SK_MSG
BPF_PROG_TYPE_RAW_TRACEPOINT
BPF_PROG_TYPE_CGROUP_SOCK_ADDR
BPF_PROG_TYPE_LWT_SEG6LOCAL
BPF_PROG_TYPE_LIRC_MODE2
BPF_PROG_TYPE_SK_REUSEPORT
BPF_PROG_TYPE_FLOW_DISSECTOR
BPF_PROG_TYPE_CGROUP_SYSCTL
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE
BPF_PROG_TYPE_CGROUP_SOCKOPT
BPF_PROG_TYPE_TRACING
BPF_PROG_TYPE_STRUCT_OPS
BPF_PROG_TYPE_EXT
BPF_PROG_TYPE_LSM
BPF_PROG_TYPE_SK_LOOKUP
) )
type BPFAttr struct { type BPFAttr struct {

View File

@ -176,6 +176,12 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize()) options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize())
options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab)) options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab))
options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab)) options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab))
if htb.Rate >= uint64(1<<32) {
options.AddRtAttr(nl.TCA_HTB_RATE64, nl.Uint64Attr(htb.Rate))
}
if htb.Ceil >= uint64(1<<32) {
options.AddRtAttr(nl.TCA_HTB_CEIL64, nl.Uint64Attr(htb.Ceil))
}
case "hfsc": case "hfsc":
hfsc := class.(*HfscClass) hfsc := class.(*HfscClass)
opt := nl.HfscCopt{} opt := nl.HfscCopt{}
@ -185,9 +191,9 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
opt.Fsc.Set(fm1/8, fd, fm2/8) opt.Fsc.Set(fm1/8, fd, fm2/8)
um1, ud, um2 := hfsc.Usc.Attrs() um1, ud, um2 := hfsc.Usc.Attrs()
opt.Usc.Set(um1/8, ud, um2/8) opt.Usc.Set(um1/8, ud, um2/8)
nl.NewRtAttrChild(options, nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc)) options.AddRtAttr(nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc))
nl.NewRtAttrChild(options, nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc)) options.AddRtAttr(nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc))
nl.NewRtAttrChild(options, nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc)) options.AddRtAttr(nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc))
} }
req.AddData(options) req.AddData(options)
return nil return nil
@ -306,6 +312,10 @@ func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, erro
htb.Quantum = opt.Quantum htb.Quantum = opt.Quantum
htb.Level = opt.Level htb.Level = opt.Level
htb.Prio = opt.Prio htb.Prio = opt.Prio
case nl.TCA_HTB_RATE64:
htb.Rate = native.Uint64(datum.Value[0:8])
case nl.TCA_HTB_CEIL64:
htb.Ceil = native.Uint64(datum.Value[0:8])
} }
} }
return detailed, nil return detailed, nil
@ -331,7 +341,6 @@ func parseHfscClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, err
func parseTcStats(data []byte) (*ClassStatistics, error) { func parseTcStats(data []byte) (*ClassStatistics, error) {
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
buf.Write(data) buf.Write(data)
native := nl.NativeEndian()
tcStats := &tcStats{} tcStats := &tcStats{}
if err := binary.Read(buf, native, tcStats); err != nil { if err := binary.Read(buf, native, tcStats); err != nil {
return nil, err return nil, err
@ -353,7 +362,6 @@ func parseTcStats(data []byte) (*ClassStatistics, error) {
func parseGnetStats(data []byte, gnetStats interface{}) error { func parseGnetStats(data []byte, gnetStats interface{}) error {
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
buf.Write(data) buf.Write(data)
native := nl.NativeEndian()
return binary.Read(buf, native, gnetStats) return binary.Read(buf, native, gnetStats)
} }

View File

@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"time"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
@ -145,16 +146,23 @@ type ConntrackFlow struct {
Forward ipTuple Forward ipTuple
Reverse ipTuple Reverse ipTuple
Mark uint32 Mark uint32
TimeStart uint64
TimeStop uint64
TimeOut uint32
} }
func (s *ConntrackFlow) String() string { func (s *ConntrackFlow) String() string {
// conntrack cmd output: // conntrack cmd output:
// udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 packets=5 bytes=532 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 packets=10 bytes=1078 mark=0 // udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 packets=5 bytes=532 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 packets=10 bytes=1078 mark=0
return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=%d", // start=2019-07-26 01:26:21.557800506 +0000 UTC stop=1970-01-01 00:00:00 +0000 UTC timeout=30(sec)
start := time.Unix(0, int64(s.TimeStart))
stop := time.Unix(0, int64(s.TimeStop))
timeout := int32(s.TimeOut)
return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=0x%x start=%v stop=%v timeout=%d(sec)",
nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol, nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol,
s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.Packets, s.Forward.Bytes, s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.Packets, s.Forward.Bytes,
s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Reverse.Packets, s.Reverse.Bytes, s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Reverse.Packets, s.Reverse.Bytes,
s.Mark) s.Mark, start, stop, timeout)
} }
// This method parse the ip tuple structure // This method parse the ip tuple structure
@ -174,25 +182,43 @@ func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) uint8 {
tpl.DstIP = v tpl.DstIP = v
} }
} }
// Skip the next 4 bytes nl.NLA_F_NESTED|nl.CTA_TUPLE_PROTO // Get total length of nested protocol-specific info.
reader.Seek(4, seekCurrent) _, _, protoInfoTotalLen := parseNfAttrTL(reader)
_, t, _, v := parseNfAttrTLV(reader) _, t, l, v := parseNfAttrTLV(reader)
// Track the number of bytes read.
protoInfoBytesRead := uint16(nl.SizeofNfattr) + l
if t == nl.CTA_PROTO_NUM { if t == nl.CTA_PROTO_NUM {
tpl.Protocol = uint8(v[0]) tpl.Protocol = uint8(v[0])
} }
// Skip some padding 3 bytes // We only parse TCP & UDP headers. Skip the others.
if tpl.Protocol != 6 && tpl.Protocol != 17 {
// skip the rest
bytesRemaining := protoInfoTotalLen - protoInfoBytesRead
reader.Seek(int64(bytesRemaining), seekCurrent)
return tpl.Protocol
}
// Skip 3 bytes of padding
reader.Seek(3, seekCurrent) reader.Seek(3, seekCurrent)
protoInfoBytesRead += 3
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
_, t, _ := parseNfAttrTL(reader) _, t, _ := parseNfAttrTL(reader)
protoInfoBytesRead += uint16(nl.SizeofNfattr)
switch t { switch t {
case nl.CTA_PROTO_SRC_PORT: case nl.CTA_PROTO_SRC_PORT:
parseBERaw16(reader, &tpl.SrcPort) parseBERaw16(reader, &tpl.SrcPort)
protoInfoBytesRead += 2
case nl.CTA_PROTO_DST_PORT: case nl.CTA_PROTO_DST_PORT:
parseBERaw16(reader, &tpl.DstPort) parseBERaw16(reader, &tpl.DstPort)
protoInfoBytesRead += 2
} }
// Skip some padding 2 byte // Skip 2 bytes of padding
reader.Seek(2, seekCurrent) reader.Seek(2, seekCurrent)
protoInfoBytesRead += 2
} }
// Skip any remaining/unknown parts of the message
bytesRemaining := protoInfoTotalLen - protoInfoBytesRead
reader.Seek(int64(bytesRemaining), seekCurrent)
return tpl.Protocol return tpl.Protocol
} }
@ -211,10 +237,14 @@ func parseNfAttrTL(r *bytes.Reader) (isNested bool, attrType, len uint16) {
binary.Read(r, nl.NativeEndian(), &attrType) binary.Read(r, nl.NativeEndian(), &attrType)
isNested = (attrType & nl.NLA_F_NESTED) == nl.NLA_F_NESTED isNested = (attrType & nl.NLA_F_NESTED) == nl.NLA_F_NESTED
attrType = attrType & (nl.NLA_F_NESTED - 1) attrType = attrType & (nl.NLA_F_NESTED - 1)
return isNested, attrType, len return isNested, attrType, len
} }
func skipNfAttrValue(r *bytes.Reader, len uint16) {
len = (len + nl.NLA_ALIGNTO - 1) & ^(nl.NLA_ALIGNTO - 1)
r.Seek(int64(len), seekCurrent)
}
func parseBERaw16(r *bytes.Reader, v *uint16) { func parseBERaw16(r *bytes.Reader, v *uint16) {
binary.Read(r, binary.BigEndian, v) binary.Read(r, binary.BigEndian, v)
} }
@ -241,6 +271,36 @@ func parseByteAndPacketCounters(r *bytes.Reader) (bytes, packets uint64) {
return return
} }
// when the flow is alive, only the timestamp_start is returned in structure
func parseTimeStamp(r *bytes.Reader, readSize uint16) (tstart, tstop uint64) {
var numTimeStamps int
oneItem := nl.SizeofNfattr + 8 // 4 bytes attr header + 8 bytes timestamp
if readSize == uint16(oneItem) {
numTimeStamps = 1
} else if readSize == 2*uint16(oneItem) {
numTimeStamps = 2
} else {
return
}
for i := 0; i < numTimeStamps; i++ {
switch _, t, _ := parseNfAttrTL(r); t {
case nl.CTA_TIMESTAMP_START:
parseBERaw64(r, &tstart)
case nl.CTA_TIMESTAMP_STOP:
parseBERaw64(r, &tstop)
default:
return
}
}
return
}
func parseTimeOut(r *bytes.Reader) (ttimeout uint32) {
parseBERaw32(r, &ttimeout)
return
}
func parseConnectionMark(r *bytes.Reader) (mark uint32) { func parseConnectionMark(r *bytes.Reader) (mark uint32) {
parseBERaw32(r, &mark) parseBERaw32(r, &mark)
return return
@ -266,25 +326,37 @@ func parseRawData(data []byte) *ConntrackFlow {
if nested, t, l := parseNfAttrTL(reader); nested { if nested, t, l := parseNfAttrTL(reader); nested {
switch t { switch t {
case nl.CTA_TUPLE_ORIG: case nl.CTA_TUPLE_ORIG:
if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP { if nested, t, l = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
parseIpTuple(reader, &s.Forward) parseIpTuple(reader, &s.Forward)
} }
case nl.CTA_TUPLE_REPLY: case nl.CTA_TUPLE_REPLY:
if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP { if nested, t, l = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
parseIpTuple(reader, &s.Reverse) parseIpTuple(reader, &s.Reverse)
} else { } else {
// Header not recognized skip it // Header not recognized skip it
reader.Seek(int64(l), seekCurrent) skipNfAttrValue(reader, l)
} }
case nl.CTA_COUNTERS_ORIG: case nl.CTA_COUNTERS_ORIG:
s.Forward.Bytes, s.Forward.Packets = parseByteAndPacketCounters(reader) s.Forward.Bytes, s.Forward.Packets = parseByteAndPacketCounters(reader)
case nl.CTA_COUNTERS_REPLY: case nl.CTA_COUNTERS_REPLY:
s.Reverse.Bytes, s.Reverse.Packets = parseByteAndPacketCounters(reader) s.Reverse.Bytes, s.Reverse.Packets = parseByteAndPacketCounters(reader)
case nl.CTA_TIMESTAMP:
s.TimeStart, s.TimeStop = parseTimeStamp(reader, l)
case nl.CTA_PROTOINFO:
skipNfAttrValue(reader, l)
default:
skipNfAttrValue(reader, l)
} }
} else { } else {
switch t { switch t {
case nl.CTA_MARK: case nl.CTA_MARK:
s.Mark = parseConnectionMark(reader) s.Mark = parseConnectionMark(reader)
case nl.CTA_TIMEOUT:
s.TimeOut = parseTimeOut(reader)
case nl.CTA_STATUS, nl.CTA_USE, nl.CTA_ID:
skipNfAttrValue(reader, l)
default:
skipNfAttrValue(reader, l)
} }
} }
} }
@ -346,23 +418,34 @@ type CustomConntrackFilter interface {
} }
type ConntrackFilter struct { type ConntrackFilter struct {
ipFilter map[ConntrackFilterType]net.IP ipNetFilter map[ConntrackFilterType]*net.IPNet
portFilter map[ConntrackFilterType]uint16 portFilter map[ConntrackFilterType]uint16
protoFilter uint8 protoFilter uint8
} }
// AddIP adds an IP to the conntrack filter // AddIPNet adds a IP subnet to the conntrack filter
func (f *ConntrackFilter) AddIP(tp ConntrackFilterType, ip net.IP) error { func (f *ConntrackFilter) AddIPNet(tp ConntrackFilterType, ipNet *net.IPNet) error {
if f.ipFilter == nil { if ipNet == nil {
f.ipFilter = make(map[ConntrackFilterType]net.IP) return fmt.Errorf("Filter attribute empty")
} }
if _, ok := f.ipFilter[tp]; ok { if f.ipNetFilter == nil {
f.ipNetFilter = make(map[ConntrackFilterType]*net.IPNet)
}
if _, ok := f.ipNetFilter[tp]; ok {
return errors.New("Filter attribute already present") return errors.New("Filter attribute already present")
} }
f.ipFilter[tp] = ip f.ipNetFilter[tp] = ipNet
return nil return nil
} }
// AddIP adds an IP to the conntrack filter
func (f *ConntrackFilter) AddIP(tp ConntrackFilterType, ip net.IP) error {
if ip == nil {
return fmt.Errorf("Filter attribute empty")
}
return f.AddIPNet(tp, NewIPNet(ip))
}
// AddPort adds a Port to the conntrack filter if the Layer 4 protocol allows it // AddPort adds a Port to the conntrack filter if the Layer 4 protocol allows it
func (f *ConntrackFilter) AddPort(tp ConntrackFilterType, port uint16) error { func (f *ConntrackFilter) AddPort(tp ConntrackFilterType, port uint16) error {
switch f.protoFilter { switch f.protoFilter {
@ -394,7 +477,7 @@ func (f *ConntrackFilter) AddProtocol(proto uint8) error {
// MatchConntrackFlow applies the filter to the flow and returns true if the flow matches the filter // MatchConntrackFlow applies the filter to the flow and returns true if the flow matches the filter
// false otherwise // false otherwise
func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool { func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
if len(f.ipFilter) == 0 && len(f.portFilter) == 0 && f.protoFilter == 0 { if len(f.ipNetFilter) == 0 && len(f.portFilter) == 0 && f.protoFilter == 0 {
// empty filter always not match // empty filter always not match
return false return false
} }
@ -408,30 +491,30 @@ func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
match := true match := true
// IP conntrack filter // IP conntrack filter
if len(f.ipFilter) > 0 { if len(f.ipNetFilter) > 0 {
// -orig-src ip Source address from original direction // -orig-src ip Source address from original direction
if elem, found := f.ipFilter[ConntrackOrigSrcIP]; found { if elem, found := f.ipNetFilter[ConntrackOrigSrcIP]; found {
match = match && elem.Equal(flow.Forward.SrcIP) match = match && elem.Contains(flow.Forward.SrcIP)
} }
// -orig-dst ip Destination address from original direction // -orig-dst ip Destination address from original direction
if elem, found := f.ipFilter[ConntrackOrigDstIP]; match && found { if elem, found := f.ipNetFilter[ConntrackOrigDstIP]; match && found {
match = match && elem.Equal(flow.Forward.DstIP) match = match && elem.Contains(flow.Forward.DstIP)
} }
// -src-nat ip Source NAT ip // -src-nat ip Source NAT ip
if elem, found := f.ipFilter[ConntrackReplySrcIP]; match && found { if elem, found := f.ipNetFilter[ConntrackReplySrcIP]; match && found {
match = match && elem.Equal(flow.Reverse.SrcIP) match = match && elem.Contains(flow.Reverse.SrcIP)
} }
// -dst-nat ip Destination NAT ip // -dst-nat ip Destination NAT ip
if elem, found := f.ipFilter[ConntrackReplyDstIP]; match && found { if elem, found := f.ipNetFilter[ConntrackReplyDstIP]; match && found {
match = match && elem.Equal(flow.Reverse.DstIP) match = match && elem.Contains(flow.Reverse.DstIP)
} }
// Match source or destination reply IP // Match source or destination reply IP
if elem, found := f.ipFilter[ConntrackReplyAnyIP]; match && found { if elem, found := f.ipNetFilter[ConntrackReplyAnyIP]; match && found {
match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP)) match = match && (elem.Contains(flow.Reverse.SrcIP) || elem.Contains(flow.Reverse.DstIP))
} }
} }

View File

@ -1,9 +1,10 @@
package netlink package netlink
import ( import (
"fmt"
"net"
"syscall" "syscall"
"fmt"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -27,6 +28,43 @@ type DevlinkDevice struct {
Attrs DevlinkDevAttrs Attrs DevlinkDevAttrs
} }
// DevlinkPortFn represents port function and its attributes
type DevlinkPortFn struct {
HwAddr net.HardwareAddr
State uint8
OpState uint8
}
// DevlinkPortFnSetAttrs represents attributes to set
type DevlinkPortFnSetAttrs struct {
FnAttrs DevlinkPortFn
HwAddrValid bool
StateValid bool
}
// DevlinkPort represents port and its attributes
type DevlinkPort struct {
BusName string
DeviceName string
PortIndex uint32
PortType uint16
NetdeviceName string
NetdevIfIndex uint32
RdmaDeviceName string
PortFlavour uint16
Fn *DevlinkPortFn
}
type DevLinkPortAddAttrs struct {
Controller uint32
SfNumber uint32
PortIndex uint32
PfNumber uint16
SfNumberValid bool
PortIndexValid bool
ControllerValid bool
}
func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) { func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
devices := make([]*DevlinkDevice, 0, len(msgs)) devices := make([]*DevlinkDevice, 0, len(msgs))
for _, m := range msgs { for _, m := range msgs {
@ -95,9 +133,9 @@ func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error
for _, a := range attrs { for _, a := range attrs {
switch a.Attr.Type { switch a.Attr.Type {
case nl.DEVLINK_ATTR_BUS_NAME: case nl.DEVLINK_ATTR_BUS_NAME:
d.BusName = string(a.Value) d.BusName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_DEV_NAME: case nl.DEVLINK_ATTR_DEV_NAME:
d.DeviceName = string(a.Value) d.DeviceName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_ESWITCH_MODE: case nl.DEVLINK_ATTR_ESWITCH_MODE:
d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value)) d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value))
case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE: case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE:
@ -126,12 +164,12 @@ func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK) req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK)
req.AddData(msg) req.AddData(msg)
b := make([]byte, len(dev.BusName)) b := make([]byte, len(dev.BusName)+1)
copy(b, dev.BusName) copy(b, dev.BusName)
data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b) data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
req.AddData(data) req.AddData(data)
b = make([]byte, len(dev.DeviceName)) b = make([]byte, len(dev.DeviceName)+1)
copy(b, dev.DeviceName) copy(b, dev.DeviceName)
data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b) data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
req.AddData(data) req.AddData(data)
@ -270,3 +308,206 @@ func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error
func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error { func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode) return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode)
} }
func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
for _, a := range attrs {
switch a.Attr.Type {
case nl.DEVLINK_ATTR_BUS_NAME:
port.BusName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_DEV_NAME:
port.DeviceName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_PORT_INDEX:
port.PortIndex = native.Uint32(a.Value)
case nl.DEVLINK_ATTR_PORT_TYPE:
port.PortType = native.Uint16(a.Value)
case nl.DEVLINK_ATTR_PORT_NETDEV_NAME:
port.NetdeviceName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX:
port.NetdevIfIndex = native.Uint32(a.Value)
case nl.DEVLINK_ATTR_PORT_IBDEV_NAME:
port.RdmaDeviceName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_PORT_FLAVOUR:
port.PortFlavour = native.Uint16(a.Value)
case nl.DEVLINK_ATTR_PORT_FUNCTION:
port.Fn = &DevlinkPortFn{}
for nested := range nl.ParseAttributes(a.Value) {
switch nested.Type {
case nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR:
port.Fn.HwAddr = nested.Value[:]
case nl.DEVLINK_PORT_FN_ATTR_STATE:
port.Fn.State = uint8(nested.Value[0])
case nl.DEVLINK_PORT_FN_ATTR_OPSTATE:
port.Fn.OpState = uint8(nested.Value[0])
}
}
}
}
return nil
}
func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
ports := make([]*DevlinkPort, 0, len(msgs))
for _, m := range msgs {
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
if err != nil {
return nil, err
}
port := &DevlinkPort{}
if err = port.parseAttributes(attrs); err != nil {
return nil, err
}
ports = append(ports, port)
}
return ports, nil
}
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
// otherwise returns an error code.
func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
if err != nil {
return nil, err
}
msg := &nl.Genlmsg{
Command: nl.DEVLINK_CMD_PORT_GET,
Version: nl.GENL_DEVLINK_VERSION,
}
req := h.newNetlinkRequest(int(f.ID),
unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
req.AddData(msg)
msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
ports, err := parseDevLinkAllPortList(msgs)
if err != nil {
return nil, err
}
return ports, nil
}
// DevLinkGetPortList provides a pointer to devlink ports and nil error,
// otherwise returns an error code.
func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
return pkgHandle.DevLinkGetAllPortList()
}
func parseDevlinkPortMsg(msgs [][]byte) (*DevlinkPort, error) {
m := msgs[0]
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
if err != nil {
return nil, err
}
port := &DevlinkPort{}
if err = port.parseAttributes(attrs); err != nil {
return nil, err
}
return port, nil
}
// DevLinkGetPortByIndexprovides a pointer to devlink device and nil error,
// otherwise returns an error code.
func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_GET, Bus, Device)
if err != nil {
return nil, err
}
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
port, err := parseDevlinkPortMsg(respmsg)
return port, err
}
// DevLinkGetPortByIndex provides a pointer to devlink portand nil error,
// otherwise returns an error code.
func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex)
}
// DevLinkPortAdd adds a devlink port and returns a port on success
// otherwise returns nil port and an error code.
func (h *Handle) DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_NEW, Bus, Device)
if err != nil {
return nil, err
}
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(Flavour)))
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(Attrs.PfNumber)))
if Flavour == nl.DEVLINK_PORT_FLAVOUR_PCI_SF && Attrs.SfNumberValid {
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_SF_NUMBER, nl.Uint32Attr(Attrs.SfNumber)))
}
if Attrs.PortIndexValid {
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(Attrs.PortIndex)))
}
if Attrs.ControllerValid {
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, nl.Uint32Attr(Attrs.Controller)))
}
respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
port, err := parseDevlinkPortMsg(respmsg)
return port, err
}
// DevLinkPortAdd adds a devlink port and returns a port on success
// otherwise returns nil port and an error code.
func DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
return pkgHandle.DevLinkPortAdd(Bus, Device, Flavour, Attrs)
}
// DevLinkPortDel deletes a devlink port and returns success or error code.
func (h *Handle) DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_DEL, Bus, Device)
if err != nil {
return err
}
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
return err
}
// DevLinkPortDel deletes a devlink port and returns success or error code.
func DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
return pkgHandle.DevLinkPortDel(Bus, Device, PortIndex)
}
// DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
// It returns 0 on success or error code.
func (h *Handle) DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_SET, Bus, Device)
if err != nil {
return err
}
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
fnAttr := nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FUNCTION|unix.NLA_F_NESTED, nil)
if FnAttrs.HwAddrValid {
fnAttr.AddRtAttr(nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, []byte(FnAttrs.FnAttrs.HwAddr))
}
if FnAttrs.StateValid {
fnAttr.AddRtAttr(nl.DEVLINK_PORT_FN_ATTR_STATE, nl.Uint8Attr(FnAttrs.FnAttrs.State))
}
req.AddData(fnAttr)
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
return err
}
// DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
// It returns 0 on success or error code.
func DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
return pkgHandle.DevlinkPortFnSet(Bus, Device, PortIndex, FnAttrs)
}

View File

@ -6,6 +6,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"net"
"syscall" "syscall"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
@ -36,6 +37,7 @@ type U32 struct {
ClassId uint32 ClassId uint32
Divisor uint32 // Divisor MUST be power of 2. Divisor uint32 // Divisor MUST be power of 2.
Hash uint32 Hash uint32
Link uint32
RedirIndex int RedirIndex int
Sel *TcU32Sel Sel *TcU32Sel
Actions []Action Actions []Action
@ -119,6 +121,131 @@ func (filter *Fw) Type() string {
return "fw" return "fw"
} }
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
Actions []Action
}
func (filter *Flower) Attrs() *FilterAttrs {
return &filter.FilterAttrs
}
func (filter *Flower) Type() string {
return "flower"
}
func (filter *Flower) encodeIP(parent *nl.RtAttr, ip net.IP, mask net.IPMask, v4Type, v6Type int, v4MaskType, v6MaskType int) {
ipType := v4Type
maskType := v4MaskType
encodeMask := mask
if mask == nil {
encodeMask = net.CIDRMask(32, 32)
}
v4IP := ip.To4()
if v4IP == nil {
ipType = v6Type
maskType = v6MaskType
if mask == nil {
encodeMask = net.CIDRMask(128, 128)
}
} else {
ip = v4IP
}
parent.AddRtAttr(ipType, ip)
parent.AddRtAttr(maskType, encodeMask)
}
func (filter *Flower) encode(parent *nl.RtAttr) error {
if filter.EthType != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_ETH_TYPE, htons(filter.EthType))
}
if filter.SrcIP != nil {
filter.encodeIP(parent, filter.SrcIP, filter.SrcIPMask,
nl.TCA_FLOWER_KEY_IPV4_SRC, nl.TCA_FLOWER_KEY_IPV6_SRC,
nl.TCA_FLOWER_KEY_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_IPV6_SRC_MASK)
}
if filter.DestIP != nil {
filter.encodeIP(parent, filter.DestIP, filter.DestIPMask,
nl.TCA_FLOWER_KEY_IPV4_DST, nl.TCA_FLOWER_KEY_IPV6_DST,
nl.TCA_FLOWER_KEY_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_IPV6_DST_MASK)
}
if filter.EncSrcIP != nil {
filter.encodeIP(parent, filter.EncSrcIP, filter.EncSrcIPMask,
nl.TCA_FLOWER_KEY_ENC_IPV4_SRC, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC,
nl.TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK)
}
if filter.EncDestIP != nil {
filter.encodeIP(parent, filter.EncDestIP, filter.EncSrcIPMask,
nl.TCA_FLOWER_KEY_ENC_IPV4_DST, nl.TCA_FLOWER_KEY_ENC_IPV6_DST,
nl.TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_DST_MASK)
}
if filter.EncDestPort != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_ENC_UDP_DST_PORT, htons(filter.EncDestPort))
}
if filter.EncKeyId != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_ENC_KEY_ID, htonl(filter.EncKeyId))
}
actionsAttr := parent.AddRtAttr(nl.TCA_FLOWER_ACT, nil)
if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
return err
}
return nil
}
func (filter *Flower) decode(data []syscall.NetlinkRouteAttr) error {
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_FLOWER_KEY_ETH_TYPE:
filter.EthType = ntohs(datum.Value)
case nl.TCA_FLOWER_KEY_IPV4_SRC, nl.TCA_FLOWER_KEY_IPV6_SRC:
filter.SrcIP = datum.Value
case nl.TCA_FLOWER_KEY_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_IPV6_SRC_MASK:
filter.SrcIPMask = datum.Value
case nl.TCA_FLOWER_KEY_IPV4_DST, nl.TCA_FLOWER_KEY_IPV6_DST:
filter.DestIP = datum.Value
case nl.TCA_FLOWER_KEY_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_IPV6_DST_MASK:
filter.DestIPMask = datum.Value
case nl.TCA_FLOWER_KEY_ENC_IPV4_SRC, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC:
filter.EncSrcIP = datum.Value
case nl.TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK:
filter.EncSrcIPMask = datum.Value
case nl.TCA_FLOWER_KEY_ENC_IPV4_DST, nl.TCA_FLOWER_KEY_ENC_IPV6_DST:
filter.EncDestIP = datum.Value
case nl.TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_DST_MASK:
filter.EncDestIPMask = datum.Value
case nl.TCA_FLOWER_KEY_ENC_UDP_DST_PORT:
filter.EncDestPort = ntohs(datum.Value)
case nl.TCA_FLOWER_KEY_ENC_KEY_ID:
filter.EncKeyId = ntohl(datum.Value)
case nl.TCA_FLOWER_ACT:
tables, err := nl.ParseRouteAttr(datum.Value)
if err != nil {
return err
}
filter.Actions, err = parseActions(tables)
if err != nil {
return err
}
}
}
return nil
}
// FilterDel will delete a filter from the system. // FilterDel will delete a filter from the system.
// Equivalent to: `tc filter del $filter` // Equivalent to: `tc filter del $filter`
func FilterDel(filter Filter) error { func FilterDel(filter Filter) error {
@ -168,7 +295,6 @@ func (h *Handle) FilterReplace(filter Filter) error {
} }
func (h *Handle) filterModify(filter Filter, flags int) error { func (h *Handle) filterModify(filter Filter, flags int) error {
native = nl.NativeEndian()
req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, flags|unix.NLM_F_ACK) req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, flags|unix.NLM_F_ACK)
base := filter.Attrs() base := filter.Attrs()
msg := &nl.TcMsg{ msg := &nl.TcMsg{
@ -225,6 +351,9 @@ func (h *Handle) filterModify(filter Filter, flags int) error {
if filter.Hash != 0 { if filter.Hash != 0 {
options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash)) options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash))
} }
if filter.Link != 0 {
options.AddRtAttr(nl.TCA_U32_LINK, nl.Uint32Attr(filter.Link))
}
actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil) actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil)
// backwards compatibility // backwards compatibility
if filter.RedirIndex != 0 { if filter.RedirIndex != 0 {
@ -283,6 +412,10 @@ func (h *Handle) filterModify(filter Filter, flags int) error {
if filter.ClassId != 0 { if filter.ClassId != 0 {
options.AddRtAttr(nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId)) options.AddRtAttr(nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId))
} }
case *Flower:
if err := filter.encode(options); err != nil {
return err
}
} }
req.AddData(options) req.AddData(options)
@ -351,6 +484,8 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
filter = &BpfFilter{} filter = &BpfFilter{}
case "matchall": case "matchall":
filter = &MatchAll{} filter = &MatchAll{}
case "flower":
filter = &Flower{}
default: default:
filter = &GenericFilter{FilterType: filterType} filter = &GenericFilter{FilterType: filterType}
} }
@ -380,6 +515,11 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
case "flower":
detailed, err = parseFlowerData(filter, data)
if err != nil {
return nil, err
}
default: default:
detailed = true detailed = true
} }
@ -628,7 +768,6 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
} }
func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
u32 := filter.(*U32) u32 := filter.(*U32)
detailed := false detailed := false
for _, datum := range data { for _, datum := range data {
@ -666,13 +805,14 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
u32.Divisor = native.Uint32(datum.Value) u32.Divisor = native.Uint32(datum.Value)
case nl.TCA_U32_HASH: case nl.TCA_U32_HASH:
u32.Hash = native.Uint32(datum.Value) u32.Hash = native.Uint32(datum.Value)
case nl.TCA_U32_LINK:
u32.Link = native.Uint32(datum.Value)
} }
} }
return detailed, nil return detailed, nil
} }
func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
fw := filter.(*Fw) fw := filter.(*Fw)
detailed := true detailed := true
for _, datum := range data { for _, datum := range data {
@ -701,7 +841,6 @@ func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
} }
func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
bpf := filter.(*BpfFilter) bpf := filter.(*BpfFilter)
detailed := true detailed := true
for _, datum := range data { for _, datum := range data {
@ -727,7 +866,6 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
} }
func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
matchall := filter.(*MatchAll) matchall := filter.(*MatchAll)
detailed := true detailed := true
for _, datum := range data { for _, datum := range data {
@ -748,6 +886,10 @@ func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, er
return detailed, nil return detailed, nil
} }
func parseFlowerData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
return true, filter.(*Flower).decode(data)
}
func AlignToAtm(size uint) uint { func AlignToAtm(size uint) uint {
var linksize, cells int var linksize, cells int
cells = int(size / nl.ATM_CELL_PAYLOAD) cells = int(size / nl.ATM_CELL_PAYLOAD)
@ -795,14 +937,12 @@ func CalcRtable(rate *nl.TcRateSpec, rtab []uint32, cellLog int, mtu uint32, lin
func DeserializeRtab(b []byte) [256]uint32 { func DeserializeRtab(b []byte) [256]uint32 {
var rtab [256]uint32 var rtab [256]uint32
native := nl.NativeEndian()
r := bytes.NewReader(b) r := bytes.NewReader(b)
_ = binary.Read(r, native, &rtab) _ = binary.Read(r, native, &rtab)
return rtab return rtab
} }
func SerializeRtab(rtab [256]uint32) []byte { func SerializeRtab(rtab [256]uint32) []byte {
native := nl.NativeEndian()
var w bytes.Buffer var w bytes.Buffer
_ = binary.Write(&w, native, rtab) _ = binary.Write(&w, native, rtab)
return w.Bytes() return w.Bytes()

View File

@ -15,12 +15,28 @@ var pkgHandle = &Handle{}
// Handle is an handle for the netlink requests on a // Handle is an handle for the netlink requests on a
// specific network namespace. All the requests on the // specific network namespace. All the requests on the
// same netlink family share the same netlink socket, // same netlink family share the same netlink socket,
// which gets released when the handle is deleted. // which gets released when the handle is Close'd.
type Handle struct { type Handle struct {
sockets map[int]*nl.SocketHandle sockets map[int]*nl.SocketHandle
lookupByDump bool lookupByDump bool
} }
// SetSocketTimeout configures timeout for default netlink sockets
func SetSocketTimeout(to time.Duration) error {
if to < time.Microsecond {
return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond)
}
nl.SocketTimeoutTv = unix.NsecToTimeval(to.Nanoseconds())
return nil
}
// GetSocketTimeout returns the timeout value used by default netlink sockets
func GetSocketTimeout() time.Duration {
nsec := unix.TimevalToNsec(nl.SocketTimeoutTv)
return time.Duration(nsec) * time.Nanosecond
}
// SupportsNetlinkFamily reports whether the passed netlink family is supported by this Handle // SupportsNetlinkFamily reports whether the passed netlink family is supported by this Handle
func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool { func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool {
_, ok := h.sockets[nlFamily] _, ok := h.sockets[nlFamily]
@ -120,14 +136,22 @@ func newHandle(newNs, curNs netns.NsHandle, nlFamilies ...int) (*Handle, error)
return h, nil return h, nil
} }
// Delete releases the resources allocated to this handle // Close releases the resources allocated to this handle
func (h *Handle) Delete() { func (h *Handle) Close() {
for _, sh := range h.sockets { for _, sh := range h.sockets {
sh.Close() sh.Close()
} }
h.sockets = nil h.sockets = nil
} }
// Delete releases the resources allocated to this handle
//
// Deprecated: use Close instead which is in line with typical resource release
// patterns for files and other resources.
func (h *Handle) Delete() {
h.Close()
}
func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest { func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest {
// Do this so that package API still use nl package variable nextSeqNr // Do this so that package API still use nl package variable nextSeqNr
if h.sockets == nil { if h.sockets == nil {

View File

@ -23,6 +23,8 @@ func NewHandleAtFrom(newNs, curNs netns.NsHandle) (*Handle, error) {
return nil, ErrNotImplemented return nil, ErrNotImplemented
} }
func (h *Handle) Close() {}
func (h *Handle) Delete() {} func (h *Handle) Delete() {}
func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool { func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool {
@ -237,6 +239,10 @@ func (h *Handle) RouteAdd(route *Route) error {
return ErrNotImplemented return ErrNotImplemented
} }
func (h *Handle) RouteAppend(route *Route) error {
return ErrNotImplemented
}
func (h *Handle) RouteDel(route *Route) error { func (h *Handle) RouteDel(route *Route) error {
return ErrNotImplemented return ErrNotImplemented
} }

View File

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

View File

@ -1,6 +1,7 @@
package netlink package netlink
import ( import (
"encoding/binary"
"log" "log"
"net" "net"
"syscall" "syscall"
@ -11,25 +12,40 @@ import (
// IPSetEntry is used for adding, updating, retreiving and deleting entries // IPSetEntry is used for adding, updating, retreiving and deleting entries
type IPSetEntry struct { type IPSetEntry struct {
Comment string Comment string
MAC net.HardwareAddr MAC net.HardwareAddr
IP net.IP IP net.IP
Timeout *uint32 CIDR uint8
Packets *uint64 Timeout *uint32
Bytes *uint64 Packets *uint64
Bytes *uint64
Protocol *uint8
Port *uint16
IP2 net.IP
CIDR2 uint8
IFace string
Mark *uint32
Replace bool // replace existing entry Replace bool // replace existing entry
} }
// IPSetResult is the result of a dump request for a set // IPSetResult is the result of a dump request for a set
type IPSetResult struct { type IPSetResult struct {
Nfgenmsg *nl.Nfgenmsg Nfgenmsg *nl.Nfgenmsg
Protocol uint8 Protocol uint8
Revision uint8 ProtocolMinVersion uint8
Family uint8 Revision uint8
Flags uint8 Family uint8
SetName string Flags uint8
TypeName string SetName string
TypeName string
Comment string
MarkMask uint32
IPFrom net.IP
IPTo net.IP
PortFrom uint16
PortTo uint16
HashSize uint32 HashSize uint32
NumEntries uint32 NumEntries uint32
@ -38,6 +54,7 @@ type IPSetResult struct {
SizeInMemory uint32 SizeInMemory uint32
CadtFlags uint32 CadtFlags uint32
Timeout *uint32 Timeout *uint32
LineNo uint32
Entries []IPSetEntry Entries []IPSetEntry
} }
@ -49,10 +66,16 @@ type IpsetCreateOptions struct {
Counters bool Counters bool
Comments bool Comments bool
Skbinfo bool Skbinfo bool
Revision uint8
IPFrom net.IP
IPTo net.IP
PortFrom uint16
PortTo uint16
} }
// IpsetProtocol returns the ipset protocol version from the kernel // IpsetProtocol returns the ipset protocol version from the kernel
func IpsetProtocol() (uint8, error) { func IpsetProtocol() (uint8, uint8, error) {
return pkgHandle.IpsetProtocol() return pkgHandle.IpsetProtocol()
} }
@ -83,23 +106,23 @@ func IpsetListAll() ([]IPSetResult, error) {
// IpsetAdd adds an entry to an existing ipset. // IpsetAdd adds an entry to an existing ipset.
func IpsetAdd(setname string, entry *IPSetEntry) error { func IpsetAdd(setname string, entry *IPSetEntry) error {
return pkgHandle.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry) return pkgHandle.IpsetAdd(setname, entry)
} }
// IpsetDele deletes an entry from an existing ipset. // IpsetDel deletes an entry from an existing ipset.
func IpsetDel(setname string, entry *IPSetEntry) error { func IpsetDel(setname string, entry *IPSetEntry) error {
return pkgHandle.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry) return pkgHandle.IpsetDel(setname, entry)
} }
func (h *Handle) IpsetProtocol() (uint8, error) { func (h *Handle) IpsetProtocol() (protocol uint8, minVersion uint8, err error) {
req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL) req := h.newIpsetRequest(nl.IPSET_CMD_PROTOCOL)
msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0) msgs, err := req.Execute(unix.NETLINK_NETFILTER, 0)
if err != nil { if err != nil {
return 0, err return 0, 0, err
} }
response := ipsetUnserialize(msgs)
return ipsetUnserialize(msgs).Protocol, nil return response.Protocol, response.ProtocolMinVersion, nil
} }
func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error { func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOptions) error {
@ -111,11 +134,30 @@ func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOption
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename)))
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(0)))
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(0))) revision := options.Revision
if revision == 0 {
revision = getIpsetDefaultWithTypeName(typename)
}
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(revision)))
data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil) data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
var family uint8
switch typename {
case "hash:mac":
case "bitmap:port":
buf := make([]byte, 4)
binary.BigEndian.PutUint16(buf, options.PortFrom)
binary.BigEndian.PutUint16(buf[2:], options.PortTo)
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PORT_FROM|int(nl.NLA_F_NET_BYTEORDER), buf[:2]))
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PORT_TO|int(nl.NLA_F_NET_BYTEORDER), buf[2:]))
default:
family = unix.AF_INET
}
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(family)))
if timeout := options.Timeout; timeout != nil { if timeout := options.Timeout; timeout != nil {
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})
} }
@ -184,9 +226,24 @@ func (h *Handle) IpsetListAll() ([]IPSetResult, error) {
return result, nil return result, nil
} }
// IpsetAdd adds an entry to an existing ipset.
func (h *Handle) IpsetAdd(setname string, entry *IPSetEntry) error {
return h.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry)
}
// IpsetDel deletes an entry from an existing ipset.
func (h *Handle) IpsetDel(setname string, entry *IPSetEntry) error {
return h.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry)
}
func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error { func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error {
req := h.newIpsetRequest(nlCmd) req := h.newIpsetRequest(nlCmd)
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname))) req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
if entry.Comment != "" {
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_COMMENT, nl.ZeroTerminated(entry.Comment)))
}
data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil) data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
if !entry.Replace { if !entry.Replace {
@ -196,10 +253,49 @@ func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error
if entry.Timeout != nil { if entry.Timeout != nil {
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout}) data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout})
} }
if entry.IP != nil {
nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP)
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NESTED), nestedData.Serialize()))
}
if entry.MAC != nil { if entry.MAC != nil {
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER, entry.MAC)) data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER, entry.MAC))
} }
if entry.CIDR != 0 {
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_CIDR, nl.Uint8Attr(entry.CIDR)))
}
if entry.IP2 != nil {
nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP2)
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP2|int(nl.NLA_F_NESTED), nestedData.Serialize()))
}
if entry.CIDR2 != 0 {
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_CIDR2, nl.Uint8Attr(entry.CIDR2)))
}
if entry.Port != nil {
if entry.Protocol == nil {
// use tcp protocol as default
val := uint8(unix.IPPROTO_TCP)
entry.Protocol = &val
}
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PROTO, nl.Uint8Attr(*entry.Protocol)))
buf := make([]byte, 2)
binary.BigEndian.PutUint16(buf, *entry.Port)
data.AddChild(nl.NewRtAttr(int(nl.IPSET_ATTR_PORT|nl.NLA_F_NET_BYTEORDER), buf))
}
if entry.IFace != "" {
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IFACE, nl.ZeroTerminated(entry.IFace)))
}
if entry.Mark != nil {
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_MARK | nl.NLA_F_NET_BYTEORDER, Value: *entry.Mark})
}
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0}) data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0})
req.AddData(data) req.AddData(data)
@ -222,6 +318,17 @@ func (h *Handle) newIpsetRequest(cmd int) *nl.NetlinkRequest {
return req return req
} }
func getIpsetDefaultWithTypeName(typename string) uint8 {
switch typename {
case "hash:ip,port",
"hash:ip,port,ip",
"hash:ip,port,net",
"hash:net,port":
return 1
}
return 0
}
func ipsetExecute(req *nl.NetlinkRequest) (msgs [][]byte, err error) { func ipsetExecute(req *nl.NetlinkRequest) (msgs [][]byte, err error) {
msgs, err = req.Execute(unix.NETLINK_NETFILTER, 0) msgs, err = req.Execute(unix.NETLINK_NETFILTER, 0)
@ -249,6 +356,8 @@ func (result *IPSetResult) unserialize(msg []byte) {
result.Protocol = attr.Value[0] result.Protocol = attr.Value[0]
case nl.IPSET_ATTR_SETNAME: case nl.IPSET_ATTR_SETNAME:
result.SetName = nl.BytesToString(attr.Value) result.SetName = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_COMMENT:
result.Comment = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_TYPENAME: case nl.IPSET_ATTR_TYPENAME:
result.TypeName = nl.BytesToString(attr.Value) result.TypeName = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_REVISION: case nl.IPSET_ATTR_REVISION:
@ -261,6 +370,10 @@ func (result *IPSetResult) unserialize(msg []byte) {
result.parseAttrData(attr.Value) result.parseAttrData(attr.Value)
case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED: case nl.IPSET_ATTR_ADT | nl.NLA_F_NESTED:
result.parseAttrADT(attr.Value) result.parseAttrADT(attr.Value)
case nl.IPSET_ATTR_PROTOCOL_MIN:
result.ProtocolMinVersion = attr.Value[0]
case nl.IPSET_ATTR_MARKMASK:
result.MarkMask = attr.Uint32()
default: default:
log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK) log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
} }
@ -285,6 +398,36 @@ func (result *IPSetResult) parseAttrData(data []byte) {
result.SizeInMemory = attr.Uint32() result.SizeInMemory = attr.Uint32()
case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER: case nl.IPSET_ATTR_CADT_FLAGS | nl.NLA_F_NET_BYTEORDER:
result.CadtFlags = attr.Uint32() result.CadtFlags = attr.Uint32()
case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
for nested := range nl.ParseAttributes(attr.Value) {
switch nested.Type {
case nl.IPSET_ATTR_IP | nl.NLA_F_NET_BYTEORDER:
result.Entries = append(result.Entries, IPSetEntry{IP: nested.Value})
case nl.IPSET_ATTR_IP:
result.IPFrom = nested.Value
default:
log.Printf("unknown nested ipset data attribute from kernel: %+v %v", nested, nested.Type&nl.NLA_TYPE_MASK)
}
}
case nl.IPSET_ATTR_IP_TO | nl.NLA_F_NESTED:
for nested := range nl.ParseAttributes(attr.Value) {
switch nested.Type {
case nl.IPSET_ATTR_IP:
result.IPTo = nested.Value
default:
log.Printf("unknown nested ipset data attribute from kernel: %+v %v", nested, nested.Type&nl.NLA_TYPE_MASK)
}
}
case nl.IPSET_ATTR_PORT_FROM | nl.NLA_F_NET_BYTEORDER:
result.PortFrom = networkOrder.Uint16(attr.Value)
case nl.IPSET_ATTR_PORT_TO | nl.NLA_F_NET_BYTEORDER:
result.PortTo = networkOrder.Uint16(attr.Value)
case nl.IPSET_ATTR_CADT_LINENO | nl.NLA_F_NET_BYTEORDER:
result.LineNo = attr.Uint32()
case nl.IPSET_ATTR_COMMENT:
result.Comment = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_MARKMASK:
result.MarkMask = attr.Uint32()
default: default:
log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK) log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
} }
@ -316,6 +459,8 @@ func parseIPSetEntry(data []byte) (entry IPSetEntry) {
entry.Packets = &val entry.Packets = &val
case nl.IPSET_ATTR_ETHER: case nl.IPSET_ATTR_ETHER:
entry.MAC = net.HardwareAddr(attr.Value) entry.MAC = net.HardwareAddr(attr.Value)
case nl.IPSET_ATTR_IP:
entry.IP = net.IP(attr.Value)
case nl.IPSET_ATTR_COMMENT: case nl.IPSET_ATTR_COMMENT:
entry.Comment = nl.BytesToString(attr.Value) entry.Comment = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED: case nl.IPSET_ATTR_IP | nl.NLA_F_NESTED:
@ -327,6 +472,30 @@ func parseIPSetEntry(data []byte) (entry IPSetEntry) {
log.Printf("unknown nested ADT attribute from kernel: %+v", attr) log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
} }
} }
case nl.IPSET_ATTR_IP2 | nl.NLA_F_NESTED:
for attr := range nl.ParseAttributes(attr.Value) {
switch attr.Type {
case nl.IPSET_ATTR_IP:
entry.IP2 = net.IP(attr.Value)
default:
log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
}
}
case nl.IPSET_ATTR_CIDR:
entry.CIDR = attr.Value[0]
case nl.IPSET_ATTR_CIDR2:
entry.CIDR2 = attr.Value[0]
case nl.IPSET_ATTR_PORT | nl.NLA_F_NET_BYTEORDER:
val := networkOrder.Uint16(attr.Value)
entry.Port = &val
case nl.IPSET_ATTR_PROTO:
val := attr.Value[0]
entry.Protocol = &val
case nl.IPSET_ATTR_IFACE:
entry.IFace = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_MARK | nl.NLA_F_NET_BYTEORDER:
val := attr.Uint32()
entry.Mark = &val
default: default:
log.Printf("unknown ADT attribute from kernel: %+v", attr) log.Printf("unknown ADT attribute from kernel: %+v", attr)
} }

View File

@ -35,10 +35,13 @@ type LinkAttrs struct {
Alias string Alias string
Statistics *LinkStatistics Statistics *LinkStatistics
Promisc int Promisc int
Allmulti int
Multi int
Xdp *LinkXdp Xdp *LinkXdp
EncapType string EncapType string
Protinfo *Protinfo Protinfo *Protinfo
OperState LinkOperState OperState LinkOperState
PhysSwitchID int
NetNsID int NetNsID int
NumTxQueues int NumTxQueues int
NumRxQueues int NumRxQueues int
@ -456,6 +459,19 @@ func (ipvlan *IPVlan) Type() string {
return "ipvlan" return "ipvlan"
} }
// IPVtap - IPVtap is a virtual interfaces based on ipvlan
type IPVtap struct {
IPVlan
}
func (ipvtap *IPVtap) Attrs() *LinkAttrs {
return &ipvtap.LinkAttrs
}
func (ipvtap IPVtap) Type() string {
return "ipvtap"
}
// VlanProtocol type // VlanProtocol type
type VlanProtocol int type VlanProtocol int
@ -555,6 +571,27 @@ const (
BOND_ARP_VALIDATE_ALL BOND_ARP_VALIDATE_ALL
) )
var bondArpValidateToString = map[BondArpValidate]string{
BOND_ARP_VALIDATE_NONE: "none",
BOND_ARP_VALIDATE_ACTIVE: "active",
BOND_ARP_VALIDATE_BACKUP: "backup",
BOND_ARP_VALIDATE_ALL: "none",
}
var StringToBondArpValidateMap = map[string]BondArpValidate{
"none": BOND_ARP_VALIDATE_NONE,
"active": BOND_ARP_VALIDATE_ACTIVE,
"backup": BOND_ARP_VALIDATE_BACKUP,
"all": BOND_ARP_VALIDATE_ALL,
}
func (b BondArpValidate) String() string {
s, ok := bondArpValidateToString[b]
if !ok {
return fmt.Sprintf("BondArpValidate(%d)", b)
}
return s
}
// BondPrimaryReselect type // BondPrimaryReselect type
type BondPrimaryReselect int type BondPrimaryReselect int
@ -565,6 +602,25 @@ const (
BOND_PRIMARY_RESELECT_FAILURE BOND_PRIMARY_RESELECT_FAILURE
) )
var bondPrimaryReselectToString = map[BondPrimaryReselect]string{
BOND_PRIMARY_RESELECT_ALWAYS: "always",
BOND_PRIMARY_RESELECT_BETTER: "better",
BOND_PRIMARY_RESELECT_FAILURE: "failure",
}
var StringToBondPrimaryReselectMap = map[string]BondPrimaryReselect{
"always": BOND_PRIMARY_RESELECT_ALWAYS,
"better": BOND_PRIMARY_RESELECT_BETTER,
"failure": BOND_PRIMARY_RESELECT_FAILURE,
}
func (b BondPrimaryReselect) String() string {
s, ok := bondPrimaryReselectToString[b]
if !ok {
return fmt.Sprintf("BondPrimaryReselect(%d)", b)
}
return s
}
// BondArpAllTargets type // BondArpAllTargets type
type BondArpAllTargets int type BondArpAllTargets int
@ -574,6 +630,23 @@ const (
BOND_ARP_ALL_TARGETS_ALL BOND_ARP_ALL_TARGETS_ALL
) )
var bondArpAllTargetsToString = map[BondArpAllTargets]string{
BOND_ARP_ALL_TARGETS_ANY: "any",
BOND_ARP_ALL_TARGETS_ALL: "all",
}
var StringToBondArpAllTargetsMap = map[string]BondArpAllTargets{
"any": BOND_ARP_ALL_TARGETS_ANY,
"all": BOND_ARP_ALL_TARGETS_ALL,
}
func (b BondArpAllTargets) String() string {
s, ok := bondArpAllTargetsToString[b]
if !ok {
return fmt.Sprintf("BondArpAllTargets(%d)", b)
}
return s
}
// BondFailOverMac type // BondFailOverMac type
type BondFailOverMac int type BondFailOverMac int
@ -584,6 +657,25 @@ const (
BOND_FAIL_OVER_MAC_FOLLOW BOND_FAIL_OVER_MAC_FOLLOW
) )
var bondFailOverMacToString = map[BondFailOverMac]string{
BOND_FAIL_OVER_MAC_NONE: "none",
BOND_FAIL_OVER_MAC_ACTIVE: "active",
BOND_FAIL_OVER_MAC_FOLLOW: "follow",
}
var StringToBondFailOverMacMap = map[string]BondFailOverMac{
"none": BOND_FAIL_OVER_MAC_NONE,
"active": BOND_FAIL_OVER_MAC_ACTIVE,
"follow": BOND_FAIL_OVER_MAC_FOLLOW,
}
func (b BondFailOverMac) String() string {
s, ok := bondFailOverMacToString[b]
if !ok {
return fmt.Sprintf("BondFailOverMac(%d)", b)
}
return s
}
// BondXmitHashPolicy type // BondXmitHashPolicy type
type BondXmitHashPolicy int type BondXmitHashPolicy int
@ -675,6 +767,25 @@ const (
BOND_AD_SELECT_COUNT BOND_AD_SELECT_COUNT
) )
var bondAdSelectToString = map[BondAdSelect]string{
BOND_AD_SELECT_STABLE: "stable",
BOND_AD_SELECT_BANDWIDTH: "bandwidth",
BOND_AD_SELECT_COUNT: "count",
}
var StringToBondAdSelectMap = map[string]BondAdSelect{
"stable": BOND_AD_SELECT_STABLE,
"bandwidth": BOND_AD_SELECT_BANDWIDTH,
"count": BOND_AD_SELECT_COUNT,
}
func (b BondAdSelect) String() string {
s, ok := bondAdSelectToString[b]
if !ok {
return fmt.Sprintf("BondAdSelect(%d)", b)
}
return s
}
// BondAdInfo represents ad info for bond // BondAdInfo represents ad info for bond
type BondAdInfo struct { type BondAdInfo struct {
AggregatorId int AggregatorId int
@ -706,7 +817,7 @@ type Bond struct {
AllSlavesActive int AllSlavesActive int
MinLinks int MinLinks int
LpInterval int LpInterval int
PackersPerSlave int PacketsPerSlave int
LacpRate BondLacpRate LacpRate BondLacpRate
AdSelect BondAdSelect AdSelect BondAdSelect
// looking at iproute tool AdInfo can only be retrived. It can't be set. // looking at iproute tool AdInfo can only be retrived. It can't be set.
@ -739,7 +850,7 @@ func NewLinkBond(atr LinkAttrs) *Bond {
AllSlavesActive: -1, AllSlavesActive: -1,
MinLinks: -1, MinLinks: -1,
LpInterval: -1, LpInterval: -1,
PackersPerSlave: -1, PacketsPerSlave: -1,
LacpRate: -1, LacpRate: -1,
AdSelect: -1, AdSelect: -1,
AdActorSysPrio: -1, AdActorSysPrio: -1,
@ -789,8 +900,10 @@ func (bond *Bond) Type() string {
type BondSlaveState uint8 type BondSlaveState uint8
const ( const (
BondStateActive = iota // Link is active. //BondStateActive Link is active.
BondStateBackup // Link is backup. BondStateActive BondSlaveState = iota
//BondStateBackup Link is backup.
BondStateBackup
) )
func (s BondSlaveState) String() string { func (s BondSlaveState) String() string {
@ -804,15 +917,19 @@ func (s BondSlaveState) String() string {
} }
} }
// BondSlaveState represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave // BondSlaveMiiStatus represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave
// attribute, which contains the status of MII link monitoring // attribute, which contains the status of MII link monitoring
type BondSlaveMiiStatus uint8 type BondSlaveMiiStatus uint8
const ( const (
BondLinkUp = iota // link is up and running. //BondLinkUp link is up and running.
BondLinkFail // link has just gone down. BondLinkUp BondSlaveMiiStatus = iota
BondLinkDown // link has been down for too long time. //BondLinkFail link has just gone down.
BondLinkBack // link is going back. BondLinkFail
//BondLinkDown link has been down for too long time.
BondLinkDown
//BondLinkBack link is going back.
BondLinkBack
) )
func (s BondSlaveMiiStatus) String() string { func (s BondSlaveMiiStatus) String() string {
@ -845,6 +962,38 @@ func (b *BondSlave) SlaveType() string {
return "bond" return "bond"
} }
type VrfSlave struct {
Table uint32
}
func (v *VrfSlave) SlaveType() string {
return "vrf"
}
// Geneve devices must specify RemoteIP and ID (VNI) on create
// https://github.com/torvalds/linux/blob/47ec5303d73ea344e84f46660fff693c57641386/drivers/net/geneve.c#L1209-L1223
type Geneve struct {
LinkAttrs
ID uint32 // vni
Remote net.IP
Ttl uint8
Tos uint8
Dport uint16
UdpCsum uint8
UdpZeroCsum6Tx uint8
UdpZeroCsum6Rx uint8
Link uint32
FlowBased bool
}
func (geneve *Geneve) Attrs() *LinkAttrs {
return &geneve.LinkAttrs
}
func (geneve *Geneve) Type() string {
return "geneve"
}
// Gretap devices must specify LocalIP and RemoteIP on create // Gretap devices must specify LocalIP and RemoteIP on create
type Gretap struct { type Gretap struct {
LinkAttrs LinkAttrs
@ -1068,6 +1217,58 @@ var StringToIPoIBMode = map[string]IPoIBMode{
"connected": IPOIB_MODE_CONNECTED, "connected": IPOIB_MODE_CONNECTED,
} }
const (
CAN_STATE_ERROR_ACTIVE = iota
CAN_STATE_ERROR_WARNING
CAN_STATE_ERROR_PASSIVE
CAN_STATE_BUS_OFF
CAN_STATE_STOPPED
CAN_STATE_SLEEPING
)
type Can struct {
LinkAttrs
BitRate uint32
SamplePoint uint32
TimeQuanta uint32
PropagationSegment uint32
PhaseSegment1 uint32
PhaseSegment2 uint32
SyncJumpWidth uint32
BitRatePreScaler uint32
Name string
TimeSegment1Min uint32
TimeSegment1Max uint32
TimeSegment2Min uint32
TimeSegment2Max uint32
SyncJumpWidthMax uint32
BitRatePreScalerMin uint32
BitRatePreScalerMax uint32
BitRatePreScalerInc uint32
ClockFrequency uint32
State uint32
Mask uint32
Flags uint32
TxError uint16
RxError uint16
RestartMs uint32
}
func (can *Can) Attrs() *LinkAttrs {
return &can.LinkAttrs
}
func (can *Can) Type() string {
return "can"
}
type IPoIB struct { type IPoIB struct {
LinkAttrs LinkAttrs
Pkey uint16 Pkey uint16
@ -1083,11 +1284,27 @@ func (ipoib *IPoIB) Type() string {
return "ipoib" return "ipoib"
} }
type BareUDP struct {
LinkAttrs
Port uint16
EtherType uint16
SrcPortMin uint16
MultiProto bool
}
func (bareudp *BareUDP) Attrs() *LinkAttrs {
return &bareudp.LinkAttrs
}
func (bareudp *BareUDP) Type() string {
return "bareudp"
}
// iproute2 supported devices; // iproute2 supported devices;
// vlan | veth | vcan | dummy | ifb | macvlan | macvtap | // vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | // bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
// gre | gretap | ip6gre | ip6gretap | vti | vti6 | nlmon | // gre | gretap | ip6gre | ip6gretap | vti | vti6 | nlmon |
// bond_slave | ipvlan | xfrm // bond_slave | ipvlan | xfrm | bareudp
// LinkNotFoundError wraps the various not found errors when // LinkNotFoundError wraps the various not found errors when
// getting/reading links. This is intended for better error // getting/reading links. This is intended for better error

View File

@ -34,14 +34,27 @@ const (
TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI
) )
var StringToTuntapModeMap = map[string]TuntapMode{
"tun": TUNTAP_MODE_TUN,
"tap": TUNTAP_MODE_TAP,
}
func (ttm TuntapMode) String() string {
switch ttm {
case TUNTAP_MODE_TUN:
return "tun"
case TUNTAP_MODE_TAP:
return "tap"
}
return "unknown"
}
const ( const (
VF_LINK_STATE_AUTO uint32 = 0 VF_LINK_STATE_AUTO uint32 = 0
VF_LINK_STATE_ENABLE uint32 = 1 VF_LINK_STATE_ENABLE uint32 = 1
VF_LINK_STATE_DISABLE uint32 = 2 VF_LINK_STATE_DISABLE uint32 = 2
) )
var lookupByDump = false
var macvlanModes = [...]uint32{ var macvlanModes = [...]uint32{
0, 0,
nl.MACVLAN_MODE_PRIVATE, nl.MACVLAN_MODE_PRIVATE,
@ -138,7 +151,6 @@ func (h *Handle) LinkSetAllmulticastOn(link Link) error {
msg := nl.NewIfInfomsg(unix.AF_UNSPEC) msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Change = unix.IFF_ALLMULTI msg.Change = unix.IFF_ALLMULTI
msg.Flags = unix.IFF_ALLMULTI msg.Flags = unix.IFF_ALLMULTI
msg.Index = int32(base.Index) msg.Index = int32(base.Index)
req.AddData(msg) req.AddData(msg)
@ -168,6 +180,51 @@ func (h *Handle) LinkSetAllmulticastOff(link Link) error {
return err return err
} }
// LinkSetMulticastOn enables the reception of multicast packets for the link device.
// Equivalent to: `ip link set $link multicast on`
func LinkSetMulticastOn(link Link) error {
return pkgHandle.LinkSetMulticastOn(link)
}
// LinkSetMulticastOn enables the reception of multicast packets for the link device.
// Equivalent to: `ip link set $link multicast on`
func (h *Handle) LinkSetMulticastOn(link Link) error {
base := link.Attrs()
h.ensureIndex(base)
req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Change = unix.IFF_MULTICAST
msg.Flags = unix.IFF_MULTICAST
msg.Index = int32(base.Index)
req.AddData(msg)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
// LinkSetAllmulticastOff disables the reception of multicast packets for the link device.
// Equivalent to: `ip link set $link multicast off`
func LinkSetMulticastOff(link Link) error {
return pkgHandle.LinkSetMulticastOff(link)
}
// LinkSetAllmulticastOff disables the reception of multicast packets for the link device.
// Equivalent to: `ip link set $link multicast off`
func (h *Handle) LinkSetMulticastOff(link Link) error {
base := link.Attrs()
h.ensureIndex(base)
req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Change = unix.IFF_MULTICAST
msg.Index = int32(base.Index)
req.AddData(msg)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
func MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error { func MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error {
return pkgHandle.MacvlanMACAddrAdd(link, addr) return pkgHandle.MacvlanMACAddrAdd(link, addr)
} }
@ -532,13 +589,13 @@ func (h *Handle) LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
req.AddData(msg) req.AddData(msg)
data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil) info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
vfmsg := nl.VfVlan{ vfmsg := nl.VfVlan{
Vf: uint32(vf), Vf: uint32(vf),
Vlan: uint32(vlan), Vlan: uint32(vlan),
Qos: uint32(qos), Qos: uint32(qos),
} }
nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize()) info.AddRtAttr(nl.IFLA_VF_VLAN, vfmsg.Serialize())
req.AddData(data) req.AddData(data)
_, err := req.Execute(unix.NETLINK_ROUTE, 0) _, err := req.Execute(unix.NETLINK_ROUTE, 0)
@ -1046,8 +1103,8 @@ func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) {
if bond.LpInterval >= 0 { if bond.LpInterval >= 0 {
data.AddRtAttr(nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval))) data.AddRtAttr(nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval)))
} }
if bond.PackersPerSlave >= 0 { if bond.PacketsPerSlave >= 0 {
data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PackersPerSlave))) data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PacketsPerSlave)))
} }
if bond.LacpRate >= 0 { if bond.LacpRate >= 0 {
data.AddRtAttr(nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate))) data.AddRtAttr(nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate)))
@ -1203,9 +1260,26 @@ func (h *Handle) linkModify(link Link, flags int) error {
} }
control := func(file *os.File, f func(fd uintptr)) error {
name := file.Name()
conn, err := file.SyscallConn()
if err != nil {
return fmt.Errorf("SyscallConn() failed on %s: %v", name, err)
}
if err := conn.Control(f); err != nil {
return fmt.Errorf("Failed to get file descriptor for %s: %v", name, err)
}
return nil
}
// only persist interface if NonPersist is NOT set // only persist interface if NonPersist is NOT set
if !tuntap.NonPersist { if !tuntap.NonPersist {
_, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1) var errno syscall.Errno
if err := control(fds[0], func(fd uintptr) {
_, _, errno = unix.Syscall(unix.SYS_IOCTL, fd, uintptr(unix.TUNSETPERSIST), 1)
}); err != nil {
return err
}
if errno != 0 { if errno != 0 {
cleanupFds(fds) cleanupFds(fds)
return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno) return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno)
@ -1222,7 +1296,10 @@ func (h *Handle) linkModify(link Link, flags int) error {
// un-persist (e.g. allow the interface to be removed) the tuntap // un-persist (e.g. allow the interface to be removed) the tuntap
// should not hurt if not set prior, condition might be not needed // should not hurt if not set prior, condition might be not needed
if !tuntap.NonPersist { if !tuntap.NonPersist {
_, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0) // ignore error
_ = control(fds[0], func(fd uintptr) {
_, _, _ = unix.Syscall(unix.SYS_IOCTL, fd, uintptr(unix.TUNSETPERSIST), 0)
})
} }
cleanupFds(fds) cleanupFds(fds)
return err return err
@ -1394,6 +1471,10 @@ func (h *Handle) linkModify(link Link, flags int) error {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode))) data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode)))
data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag))) data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag)))
case *IPVtap:
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode)))
data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag)))
case *Macvlan: case *Macvlan:
if link.Mode != MACVLAN_MODE_DEFAULT { if link.Mode != MACVLAN_MODE_DEFAULT {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
@ -1404,6 +1485,8 @@ func (h *Handle) linkModify(link Link, flags int) error {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
} }
case *Geneve:
addGeneveAttrs(link, linkInfo)
case *Gretap: case *Gretap:
addGretapAttrs(link, linkInfo) addGretapAttrs(link, linkInfo)
case *Iptun: case *Iptun:
@ -1426,6 +1509,8 @@ func (h *Handle) linkModify(link Link, flags int) error {
addXfrmiAttrs(link, linkInfo) addXfrmiAttrs(link, linkInfo)
case *IPoIB: case *IPoIB:
addIPoIBAttrs(link, linkInfo) addIPoIBAttrs(link, linkInfo)
case *BareUDP:
addBareUDPAttrs(link, linkInfo)
} }
req.AddData(linkInfo) req.AddData(linkInfo)
@ -1607,7 +1692,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
} }
} }
// linkDeserialize deserializes a raw message received from netlink into // LinkDeserialize deserializes a raw message received from netlink into
// a link object. // a link object.
func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
msg := nl.DeserializeIfInfomsg(m) msg := nl.DeserializeIfInfomsg(m)
@ -1625,6 +1710,13 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
if msg.Flags&unix.IFF_PROMISC != 0 { if msg.Flags&unix.IFF_PROMISC != 0 {
base.Promisc = 1 base.Promisc = 1
} }
if msg.Flags&unix.IFF_ALLMULTI != 0 {
base.Allmulti = 1
}
if msg.Flags&unix.IFF_MULTICAST != 0 {
base.Multi = 1
}
var ( var (
link Link link Link
stats32 *LinkStatistics32 stats32 *LinkStatistics32
@ -1663,10 +1755,14 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &Bond{} link = &Bond{}
case "ipvlan": case "ipvlan":
link = &IPVlan{} link = &IPVlan{}
case "ipvtap":
link = &IPVtap{}
case "macvlan": case "macvlan":
link = &Macvlan{} link = &Macvlan{}
case "macvtap": case "macvtap":
link = &Macvtap{} link = &Macvtap{}
case "geneve":
link = &Geneve{}
case "gretap": case "gretap":
link = &Gretap{} link = &Gretap{}
case "ip6gretap": case "ip6gretap":
@ -1693,6 +1789,10 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &Tuntap{} link = &Tuntap{}
case "ipoib": case "ipoib":
link = &IPoIB{} link = &IPoIB{}
case "can":
link = &Can{}
case "bareudp":
link = &BareUDP{}
default: default:
link = &GenericLink{LinkType: linkType} link = &GenericLink{LinkType: linkType}
} }
@ -1710,10 +1810,14 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
parseBondData(link, data) parseBondData(link, data)
case "ipvlan": case "ipvlan":
parseIPVlanData(link, data) parseIPVlanData(link, data)
case "ipvtap":
parseIPVtapData(link, data)
case "macvlan": case "macvlan":
parseMacvlanData(link, data) parseMacvlanData(link, data)
case "macvtap": case "macvtap":
parseMacvtapData(link, data) parseMacvtapData(link, data)
case "geneve":
parseGeneveData(link, data)
case "gretap": case "gretap":
parseGretapData(link, data) parseGretapData(link, data)
case "ip6gretap": case "ip6gretap":
@ -1742,13 +1846,21 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
parseTuntapData(link, data) parseTuntapData(link, data)
case "ipoib": case "ipoib":
parseIPoIBData(link, data) parseIPoIBData(link, data)
case "can":
parseCanData(link, data)
case "bareudp":
parseBareUDPData(link, data)
} }
case nl.IFLA_INFO_SLAVE_KIND: case nl.IFLA_INFO_SLAVE_KIND:
slaveType = string(info.Value[:len(info.Value)-1]) slaveType = string(info.Value[:len(info.Value)-1])
switch slaveType { switch slaveType {
case "bond": case "bond":
linkSlave = &BondSlave{} linkSlave = &BondSlave{}
case "vrf":
linkSlave = &VrfSlave{}
} }
case nl.IFLA_INFO_SLAVE_DATA: case nl.IFLA_INFO_SLAVE_DATA:
switch slaveType { switch slaveType {
case "bond": case "bond":
@ -1757,6 +1869,12 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
return nil, err return nil, err
} }
parseBondSlaveData(linkSlave, data) parseBondSlaveData(linkSlave, data)
case "vrf":
data, err := nl.ParseRouteAttr(info.Value)
if err != nil {
return nil, err
}
parseVrfSlaveData(linkSlave, data)
} }
} }
} }
@ -1810,6 +1928,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
} }
case unix.IFLA_OPERSTATE: case unix.IFLA_OPERSTATE:
base.OperState = LinkOperState(uint8(attr.Value[0])) base.OperState = LinkOperState(uint8(attr.Value[0]))
case unix.IFLA_PHYS_SWITCH_ID:
base.PhysSwitchID = int(native.Uint32(attr.Value[0:4]))
case unix.IFLA_LINK_NETNSID: case unix.IFLA_LINK_NETNSID:
base.NetNsID = int(native.Uint32(attr.Value[0:4])) base.NetNsID = int(native.Uint32(attr.Value[0:4]))
case unix.IFLA_GSO_MAX_SIZE: case unix.IFLA_GSO_MAX_SIZE:
@ -1998,7 +2118,8 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
msgs, from, err := s.Receive() msgs, from, err := s.Receive()
if err != nil { if err != nil {
if cberr != nil { if cberr != nil {
cberr(err) cberr(fmt.Errorf("Receive failed: %v",
err))
} }
return return
} }
@ -2013,15 +2134,15 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
continue continue
} }
if m.Header.Type == unix.NLMSG_ERROR { if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4])) error := int32(native.Uint32(m.Data[0:4]))
if error == 0 { if error == 0 {
continue continue
} }
if cberr != nil { if cberr != nil {
cberr(syscall.Errno(-error)) cberr(fmt.Errorf("error message: %v",
syscall.Errno(-error)))
} }
return continue
} }
ifmsg := nl.DeserializeIfInfomsg(m.Data) ifmsg := nl.DeserializeIfInfomsg(m.Data)
header := unix.NlMsghdr(m.Header) header := unix.NlMsghdr(m.Header)
@ -2030,7 +2151,7 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
if cberr != nil { if cberr != nil {
cberr(err) cberr(err)
} }
return continue
} }
ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: header, Link: link} ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: header, Link: link}
} }
@ -2299,7 +2420,7 @@ func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_BOND_LP_INTERVAL: case nl.IFLA_BOND_LP_INTERVAL:
bond.LpInterval = int(native.Uint32(data[i].Value[0:4])) bond.LpInterval = int(native.Uint32(data[i].Value[0:4]))
case nl.IFLA_BOND_PACKETS_PER_SLAVE: case nl.IFLA_BOND_PACKETS_PER_SLAVE:
bond.PackersPerSlave = int(native.Uint32(data[i].Value[0:4])) bond.PacketsPerSlave = int(native.Uint32(data[i].Value[0:4]))
case nl.IFLA_BOND_AD_LACP_RATE: case nl.IFLA_BOND_AD_LACP_RATE:
bond.LacpRate = BondLacpRate(data[i].Value[0]) bond.LacpRate = BondLacpRate(data[i].Value[0])
case nl.IFLA_BOND_AD_SELECT: case nl.IFLA_BOND_AD_SELECT:
@ -2379,6 +2500,16 @@ func parseBondSlaveData(slave LinkSlave, data []syscall.NetlinkRouteAttr) {
} }
} }
func parseVrfSlaveData(slave LinkSlave, data []syscall.NetlinkRouteAttr) {
vrfSlave := slave.(*VrfSlave)
for i := range data {
switch data[i].Attr.Type {
case nl.IFLA_BOND_SLAVE_STATE:
vrfSlave.Table = native.Uint32(data[i].Value[0:4])
}
}
}
func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) { func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
ipv := link.(*IPVlan) ipv := link.(*IPVlan)
for _, datum := range data { for _, datum := range data {
@ -2391,6 +2522,18 @@ func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
} }
} }
func parseIPVtapData(link Link, data []syscall.NetlinkRouteAttr) {
ipv := link.(*IPVtap)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_IPVLAN_MODE:
ipv.Mode = IPVlanMode(native.Uint32(datum.Value[0:4]))
case nl.IFLA_IPVLAN_FLAG:
ipv.Flag = IPVlanFlag(native.Uint32(datum.Value[0:4]))
}
}
}
func parseMacvtapData(link Link, data []syscall.NetlinkRouteAttr) { func parseMacvtapData(link Link, data []syscall.NetlinkRouteAttr) {
macv := link.(*Macvtap) macv := link.(*Macvtap)
parseMacvlanData(&macv.Macvlan, data) parseMacvlanData(&macv.Macvlan, data)
@ -2448,6 +2591,58 @@ func linkFlags(rawFlags uint32) net.Flags {
return f return f
} }
func addGeneveAttrs(geneve *Geneve, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
if geneve.FlowBased {
// In flow based mode, no other attributes need to be configured
linkInfo.AddRtAttr(nl.IFLA_GENEVE_COLLECT_METADATA, boolAttr(geneve.FlowBased))
return
}
if ip := geneve.Remote; ip != nil {
if ip4 := ip.To4(); ip4 != nil {
data.AddRtAttr(nl.IFLA_GENEVE_REMOTE, ip.To4())
} else {
data.AddRtAttr(nl.IFLA_GENEVE_REMOTE6, []byte(ip))
}
}
if geneve.ID != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_ID, nl.Uint32Attr(geneve.ID))
}
if geneve.Dport != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_PORT, htons(geneve.Dport))
}
if geneve.Ttl != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_TTL, nl.Uint8Attr(geneve.Ttl))
}
if geneve.Tos != 0 {
data.AddRtAttr(nl.IFLA_GENEVE_TOS, nl.Uint8Attr(geneve.Tos))
}
}
func parseGeneveData(link Link, data []syscall.NetlinkRouteAttr) {
geneve := link.(*Geneve)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_GENEVE_ID:
geneve.ID = native.Uint32(datum.Value[0:4])
case nl.IFLA_GENEVE_REMOTE, nl.IFLA_GENEVE_REMOTE6:
geneve.Remote = datum.Value
case nl.IFLA_GENEVE_PORT:
geneve.Dport = ntohs(datum.Value[0:2])
case nl.IFLA_GENEVE_TTL:
geneve.Ttl = uint8(datum.Value[0])
case nl.IFLA_GENEVE_TOS:
geneve.Tos = uint8(datum.Value[0])
}
}
}
func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) { func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
@ -2679,6 +2874,10 @@ func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) {
func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) { func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
iptun := link.(*Iptun) iptun := link.(*Iptun)
for _, datum := range data { for _, datum := range data {
// NOTE: same with vxlan, ip tunnel may also has null datum.Value
if len(datum.Value) == 0 {
continue
}
switch datum.Attr.Type { switch datum.Attr.Type {
case nl.IFLA_IPTUN_LOCAL: case nl.IFLA_IPTUN_LOCAL:
iptun.Local = net.IP(datum.Value[0:4]) iptun.Local = net.IP(datum.Value[0:4])
@ -3172,9 +3371,86 @@ func parseIPoIBData(link Link, data []syscall.NetlinkRouteAttr) {
} }
} }
func parseCanData(link Link, data []syscall.NetlinkRouteAttr) {
can := link.(*Can)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_CAN_BITTIMING:
can.BitRate = native.Uint32(datum.Value)
can.SamplePoint = native.Uint32(datum.Value[4:])
can.TimeQuanta = native.Uint32(datum.Value[8:])
can.PropagationSegment = native.Uint32(datum.Value[12:])
can.PhaseSegment1 = native.Uint32(datum.Value[16:])
can.PhaseSegment2 = native.Uint32(datum.Value[20:])
can.SyncJumpWidth = native.Uint32(datum.Value[24:])
can.BitRatePreScaler = native.Uint32(datum.Value[28:])
case nl.IFLA_CAN_BITTIMING_CONST:
can.Name = string(datum.Value[:16])
can.TimeSegment1Min = native.Uint32(datum.Value[16:])
can.TimeSegment1Max = native.Uint32(datum.Value[20:])
can.TimeSegment2Min = native.Uint32(datum.Value[24:])
can.TimeSegment2Max = native.Uint32(datum.Value[28:])
can.SyncJumpWidthMax = native.Uint32(datum.Value[32:])
can.BitRatePreScalerMin = native.Uint32(datum.Value[36:])
can.BitRatePreScalerMax = native.Uint32(datum.Value[40:])
can.BitRatePreScalerInc = native.Uint32(datum.Value[44:])
case nl.IFLA_CAN_CLOCK:
can.ClockFrequency = native.Uint32(datum.Value)
case nl.IFLA_CAN_STATE:
can.State = native.Uint32(datum.Value)
case nl.IFLA_CAN_CTRLMODE:
can.Mask = native.Uint32(datum.Value)
can.Flags = native.Uint32(datum.Value[4:])
case nl.IFLA_CAN_BERR_COUNTER:
can.TxError = native.Uint16(datum.Value)
can.RxError = native.Uint16(datum.Value[2:])
case nl.IFLA_CAN_RESTART_MS:
can.RestartMs = native.Uint32(datum.Value)
case nl.IFLA_CAN_DATA_BITTIMING_CONST:
case nl.IFLA_CAN_RESTART:
case nl.IFLA_CAN_DATA_BITTIMING:
case nl.IFLA_CAN_TERMINATION:
case nl.IFLA_CAN_TERMINATION_CONST:
case nl.IFLA_CAN_BITRATE_CONST:
case nl.IFLA_CAN_DATA_BITRATE_CONST:
case nl.IFLA_CAN_BITRATE_MAX:
}
}
}
func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) { func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_IPOIB_PKEY, nl.Uint16Attr(uint16(ipoib.Pkey))) data.AddRtAttr(nl.IFLA_IPOIB_PKEY, nl.Uint16Attr(uint16(ipoib.Pkey)))
data.AddRtAttr(nl.IFLA_IPOIB_MODE, nl.Uint16Attr(uint16(ipoib.Mode))) data.AddRtAttr(nl.IFLA_IPOIB_MODE, nl.Uint16Attr(uint16(ipoib.Mode)))
data.AddRtAttr(nl.IFLA_IPOIB_UMCAST, nl.Uint16Attr(uint16(ipoib.Umcast))) data.AddRtAttr(nl.IFLA_IPOIB_UMCAST, nl.Uint16Attr(uint16(ipoib.Umcast)))
} }
func addBareUDPAttrs(bareudp *BareUDP, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_BAREUDP_PORT, nl.Uint16Attr(nl.Swap16(bareudp.Port)))
data.AddRtAttr(nl.IFLA_BAREUDP_ETHERTYPE, nl.Uint16Attr(nl.Swap16(bareudp.EtherType)))
if bareudp.SrcPortMin != 0 {
data.AddRtAttr(nl.IFLA_BAREUDP_SRCPORT_MIN, nl.Uint16Attr(bareudp.SrcPortMin))
}
if bareudp.MultiProto {
data.AddRtAttr(nl.IFLA_BAREUDP_MULTIPROTO_MODE, []byte{})
}
}
func parseBareUDPData(link Link, data []syscall.NetlinkRouteAttr) {
bareudp := link.(*BareUDP)
for _, attr := range data {
switch attr.Attr.Type {
case nl.IFLA_BAREUDP_PORT:
bareudp.Port = binary.BigEndian.Uint16(attr.Value)
case nl.IFLA_BAREUDP_ETHERTYPE:
bareudp.EtherType = binary.BigEndian.Uint16(attr.Value)
case nl.IFLA_BAREUDP_SRCPORT_MIN:
bareudp.SrcPortMin = native.Uint16(attr.Value)
case nl.IFLA_BAREUDP_MULTIPROTO_MODE:
bareudp.MultiProto = true
}
}
}

View File

@ -42,11 +42,12 @@ const (
// Neighbor Flags // Neighbor Flags
const ( const (
NTF_USE = 0x01 NTF_USE = 0x01
NTF_SELF = 0x02 NTF_SELF = 0x02
NTF_MASTER = 0x04 NTF_MASTER = 0x04
NTF_PROXY = 0x08 NTF_PROXY = 0x08
NTF_ROUTER = 0x80 NTF_EXT_LEARNED = 0x10
NTF_ROUTER = 0x80
) )
// Ndmsg is for adding, removing or receiving information about a neighbor table entry // Ndmsg is for adding, removing or receiving information about a neighbor table entry
@ -408,7 +409,6 @@ func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <
continue continue
} }
if m.Header.Type == unix.NLMSG_ERROR { if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4])) error := int32(native.Uint32(m.Data[0:4]))
if error == 0 { if error == 0 {
continue continue

View File

@ -180,14 +180,30 @@ func RouteAdd(route *Route) error {
return ErrNotImplemented return ErrNotImplemented
} }
func RouteAppend(route *Route) error {
return ErrNotImplemented
}
func RouteDel(route *Route) error { func RouteDel(route *Route) error {
return ErrNotImplemented return ErrNotImplemented
} }
func RouteGet(destination net.IP) ([]Route, error) {
return nil, ErrNotImplemented
}
func RouteList(link Link, family int) ([]Route, error) { func RouteList(link Link, family int) ([]Route, error) {
return nil, ErrNotImplemented return nil, ErrNotImplemented
} }
func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
return nil, ErrNotImplemented
}
func RouteReplace(route *Route) error {
return ErrNotImplemented
}
func XfrmPolicyAdd(policy *XfrmPolicy) error { func XfrmPolicyAdd(policy *XfrmPolicy) error {
return ErrNotImplemented return ErrNotImplemented
} }

View File

@ -87,7 +87,7 @@ func (h *Handle) getNetNsId(attrType int, val uint32) (int, error) {
rtgen := nl.NewRtGenMsg() rtgen := nl.NewRtGenMsg()
req.AddData(rtgen) req.AddData(rtgen)
b := make([]byte, 4, 4) b := make([]byte, 4)
native.PutUint32(b, val) native.PutUint32(b, val)
attr := nl.NewRtAttr(attrType, b) attr := nl.NewRtAttr(attrType, b)
req.AddData(attr) req.AddData(attr)
@ -126,12 +126,12 @@ func (h *Handle) setNetNsId(attrType int, val uint32, newnsid uint32) error {
rtgen := nl.NewRtGenMsg() rtgen := nl.NewRtGenMsg()
req.AddData(rtgen) req.AddData(rtgen)
b := make([]byte, 4, 4) b := make([]byte, 4)
native.PutUint32(b, val) native.PutUint32(b, val)
attr := nl.NewRtAttr(attrType, b) attr := nl.NewRtAttr(attrType, b)
req.AddData(attr) req.AddData(attr)
b1 := make([]byte, 4, 4) b1 := make([]byte, 4)
native.PutUint32(b1, newnsid) native.PutUint32(b1, newnsid)
attr1 := nl.NewRtAttr(NETNSA_NSID, b1) attr1 := nl.NewRtAttr(NETNSA_NSID, b1)
req.AddData(attr1) req.AddData(attr1)

View File

@ -44,6 +44,7 @@ const (
NLA_F_NESTED uint16 = (1 << 15) // #define NLA_F_NESTED (1 << 15) NLA_F_NESTED uint16 = (1 << 15) // #define NLA_F_NESTED (1 << 15)
NLA_F_NET_BYTEORDER uint16 = (1 << 14) // #define NLA_F_NESTED (1 << 14) NLA_F_NET_BYTEORDER uint16 = (1 << 14) // #define NLA_F_NESTED (1 << 14)
NLA_TYPE_MASK = ^(NLA_F_NESTED | NLA_F_NET_BYTEORDER) NLA_TYPE_MASK = ^(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
NLA_ALIGNTO uint16 = 4 // #define NLA_ALIGNTO 4
) )
// enum ctattr_type { // enum ctattr_type {

View File

@ -10,16 +10,30 @@ const (
const ( const (
DEVLINK_CMD_GET = 1 DEVLINK_CMD_GET = 1
DEVLINK_CMD_PORT_GET = 5
DEVLINK_CMD_PORT_SET = 6
DEVLINK_CMD_PORT_NEW = 7
DEVLINK_CMD_PORT_DEL = 8
DEVLINK_CMD_ESWITCH_GET = 29 DEVLINK_CMD_ESWITCH_GET = 29
DEVLINK_CMD_ESWITCH_SET = 30 DEVLINK_CMD_ESWITCH_SET = 30
) )
const ( const (
DEVLINK_ATTR_BUS_NAME = 1 DEVLINK_ATTR_BUS_NAME = 1
DEVLINK_ATTR_DEV_NAME = 2 DEVLINK_ATTR_DEV_NAME = 2
DEVLINK_ATTR_ESWITCH_MODE = 25 DEVLINK_ATTR_PORT_INDEX = 3
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26 DEVLINK_ATTR_PORT_TYPE = 4
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62 DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
DEVLINK_ATTR_ESWITCH_MODE = 25
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
DEVLINK_ATTR_PORT_FLAVOUR = 77
DEVLINK_ATTR_PORT_PCI_PF_NUMBER = 127
DEVLINK_ATTR_PORT_FUNCTION = 145
DEVLINK_ATTR_PORT_CONTROLLER_NUMBER = 150
DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 164
) )
const ( const (
@ -38,3 +52,37 @@ const (
DEVLINK_ESWITCH_ENCAP_MODE_NONE = 0 DEVLINK_ESWITCH_ENCAP_MODE_NONE = 0
DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1 DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1
) )
const (
DEVLINK_PORT_FLAVOUR_PHYSICAL = 0
DEVLINK_PORT_FLAVOUR_CPU = 1
DEVLINK_PORT_FLAVOUR_DSA = 2
DEVLINK_PORT_FLAVOUR_PCI_PF = 3
DEVLINK_PORT_FLAVOUR_PCI_VF = 4
DEVLINK_PORT_FLAVOUR_VIRTUAL = 5
DEVLINK_PORT_FLAVOUR_UNUSED = 6
DEVLINK_PORT_FLAVOUR_PCI_SF = 7
)
const (
DEVLINK_PORT_TYPE_NOTSET = 0
DEVLINK_PORT_TYPE_AUTO = 1
DEVLINK_PORT_TYPE_ETH = 2
DEVLINK_PORT_TYPE_IB = 3
)
const (
DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR = 1
DEVLINK_PORT_FN_ATTR_STATE = 2
DEVLINK_PORT_FN_ATTR_OPSTATE = 3
)
const (
DEVLINK_PORT_FN_STATE_INACTIVE = 0
DEVLINK_PORT_FN_STATE_ACTIVE = 1
)
const (
DEVLINK_PORT_FN_OPSTATE_DETACHED = 0
DEVLINK_PORT_FN_OPSTATE_ATTACHED = 1
)

View File

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

View File

@ -0,0 +1,29 @@
package nl
const (
LWT_BPF_PROG_UNSPEC = iota
LWT_BPF_PROG_FD
LWT_BPF_PROG_NAME
__LWT_BPF_PROG_MAX
)
const (
LWT_BPF_PROG_MAX = __LWT_BPF_PROG_MAX - 1
)
const (
LWT_BPF_UNSPEC = iota
LWT_BPF_IN
LWT_BPF_OUT
LWT_BPF_XMIT
LWT_BPF_XMIT_HEADROOM
__LWT_BPF_MAX
)
const (
LWT_BPF_MAX = __LWT_BPF_MAX - 1
)
const (
LWT_BPF_MAX_HEADROOM = 256
)

View File

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

View File

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

View File

@ -11,6 +11,8 @@ 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_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
) )
@ -30,6 +32,8 @@ const (
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_LINK_TYPE = 65
RDMA_NLDEV_SYS_ATTR_NETNS_MODE = 66 RDMA_NLDEV_SYS_ATTR_NETNS_MODE = 66
RDMA_NLDEV_NET_NS_FD = 68 RDMA_NLDEV_NET_NS_FD = 68
) )

View File

@ -23,7 +23,7 @@ func (s1 *IPv6SrHdr) Equal(s2 IPv6SrHdr) bool {
return false return false
} }
for i := range s1.Segments { for i := range s1.Segments {
if s1.Segments[i].Equal(s2.Segments[i]) != true { if !s1.Segments[i].Equal(s2.Segments[i]) {
return false return false
} }
} }
@ -89,7 +89,7 @@ func DecodeSEG6Encap(buf []byte) (int, []net.IP, error) {
} }
buf = buf[12:] buf = buf[12:]
if len(buf)%16 != 0 { if len(buf)%16 != 0 {
err := fmt.Errorf("DecodeSEG6Encap: error parsing Segment List (buf len: %d)\n", len(buf)) err := fmt.Errorf("DecodeSEG6Encap: error parsing Segment List (buf len: %d)", len(buf))
return mode, nil, err return mode, nil, err
} }
for len(buf) > 0 { for len(buf) > 0 {

View File

@ -1,6 +1,6 @@
package nl package nl
// syscall package lack of rule atributes type. // syscall package lack of rule attributes type.
// Thus there are defined below // Thus there are defined below
const ( const (
FRA_UNSPEC = iota FRA_UNSPEC = iota

View File

@ -882,6 +882,111 @@ const (
TCA_HFSC_USC TCA_HFSC_USC
) )
const (
TCA_FLOWER_UNSPEC = iota
TCA_FLOWER_CLASSID
TCA_FLOWER_INDEV
TCA_FLOWER_ACT
TCA_FLOWER_KEY_ETH_DST /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_DST_MASK /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_SRC /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_SRC_MASK /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_TYPE /* be16 */
TCA_FLOWER_KEY_IP_PROTO /* u8 */
TCA_FLOWER_KEY_IPV4_SRC /* be32 */
TCA_FLOWER_KEY_IPV4_SRC_MASK /* be32 */
TCA_FLOWER_KEY_IPV4_DST /* be32 */
TCA_FLOWER_KEY_IPV4_DST_MASK /* be32 */
TCA_FLOWER_KEY_IPV6_SRC /* struct in6_addr */
TCA_FLOWER_KEY_IPV6_SRC_MASK /* struct in6_addr */
TCA_FLOWER_KEY_IPV6_DST /* struct in6_addr */
TCA_FLOWER_KEY_IPV6_DST_MASK /* struct in6_addr */
TCA_FLOWER_KEY_TCP_SRC /* be16 */
TCA_FLOWER_KEY_TCP_DST /* be16 */
TCA_FLOWER_KEY_UDP_SRC /* be16 */
TCA_FLOWER_KEY_UDP_DST /* be16 */
TCA_FLOWER_FLAGS
TCA_FLOWER_KEY_VLAN_ID /* be16 */
TCA_FLOWER_KEY_VLAN_PRIO /* u8 */
TCA_FLOWER_KEY_VLAN_ETH_TYPE /* be16 */
TCA_FLOWER_KEY_ENC_KEY_ID /* be32 */
TCA_FLOWER_KEY_ENC_IPV4_SRC /* be32 */
TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK /* be32 */
TCA_FLOWER_KEY_ENC_IPV4_DST /* be32 */
TCA_FLOWER_KEY_ENC_IPV4_DST_MASK /* be32 */
TCA_FLOWER_KEY_ENC_IPV6_SRC /* struct in6_addr */
TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK /* struct in6_addr */
TCA_FLOWER_KEY_ENC_IPV6_DST /* struct in6_addr */
TCA_FLOWER_KEY_ENC_IPV6_DST_MASK /* struct in6_addr */
TCA_FLOWER_KEY_TCP_SRC_MASK /* be16 */
TCA_FLOWER_KEY_TCP_DST_MASK /* be16 */
TCA_FLOWER_KEY_UDP_SRC_MASK /* be16 */
TCA_FLOWER_KEY_UDP_DST_MASK /* be16 */
TCA_FLOWER_KEY_SCTP_SRC_MASK /* be16 */
TCA_FLOWER_KEY_SCTP_DST_MASK /* be16 */
TCA_FLOWER_KEY_SCTP_SRC /* be16 */
TCA_FLOWER_KEY_SCTP_DST /* be16 */
TCA_FLOWER_KEY_ENC_UDP_SRC_PORT /* be16 */
TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK /* be16 */
TCA_FLOWER_KEY_ENC_UDP_DST_PORT /* be16 */
TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK /* be16 */
TCA_FLOWER_KEY_FLAGS /* be32 */
TCA_FLOWER_KEY_FLAGS_MASK /* be32 */
TCA_FLOWER_KEY_ICMPV4_CODE /* u8 */
TCA_FLOWER_KEY_ICMPV4_CODE_MASK /* u8 */
TCA_FLOWER_KEY_ICMPV4_TYPE /* u8 */
TCA_FLOWER_KEY_ICMPV4_TYPE_MASK /* u8 */
TCA_FLOWER_KEY_ICMPV6_CODE /* u8 */
TCA_FLOWER_KEY_ICMPV6_CODE_MASK /* u8 */
TCA_FLOWER_KEY_ICMPV6_TYPE /* u8 */
TCA_FLOWER_KEY_ICMPV6_TYPE_MASK /* u8 */
TCA_FLOWER_KEY_ARP_SIP /* be32 */
TCA_FLOWER_KEY_ARP_SIP_MASK /* be32 */
TCA_FLOWER_KEY_ARP_TIP /* be32 */
TCA_FLOWER_KEY_ARP_TIP_MASK /* be32 */
TCA_FLOWER_KEY_ARP_OP /* u8 */
TCA_FLOWER_KEY_ARP_OP_MASK /* u8 */
TCA_FLOWER_KEY_ARP_SHA /* ETH_ALEN */
TCA_FLOWER_KEY_ARP_SHA_MASK /* ETH_ALEN */
TCA_FLOWER_KEY_ARP_THA /* ETH_ALEN */
TCA_FLOWER_KEY_ARP_THA_MASK /* ETH_ALEN */
TCA_FLOWER_KEY_MPLS_TTL /* u8 - 8 bits */
TCA_FLOWER_KEY_MPLS_BOS /* u8 - 1 bit */
TCA_FLOWER_KEY_MPLS_TC /* u8 - 3 bits */
TCA_FLOWER_KEY_MPLS_LABEL /* be32 - 20 bits */
TCA_FLOWER_KEY_TCP_FLAGS /* be16 */
TCA_FLOWER_KEY_TCP_FLAGS_MASK /* be16 */
TCA_FLOWER_KEY_IP_TOS /* u8 */
TCA_FLOWER_KEY_IP_TOS_MASK /* u8 */
TCA_FLOWER_KEY_IP_TTL /* u8 */
TCA_FLOWER_KEY_IP_TTL_MASK /* u8 */
TCA_FLOWER_KEY_CVLAN_ID /* be16 */
TCA_FLOWER_KEY_CVLAN_PRIO /* u8 */
TCA_FLOWER_KEY_CVLAN_ETH_TYPE /* be16 */
TCA_FLOWER_KEY_ENC_IP_TOS /* u8 */
TCA_FLOWER_KEY_ENC_IP_TOS_MASK /* u8 */
TCA_FLOWER_KEY_ENC_IP_TTL /* u8 */
TCA_FLOWER_KEY_ENC_IP_TTL_MASK /* u8 */
TCA_FLOWER_KEY_ENC_OPTS
TCA_FLOWER_KEY_ENC_OPTS_MASK
__TCA_FLOWER_MAX
)
// struct tc_sfq_qopt { // struct tc_sfq_qopt {
// unsigned quantum; /* Bytes per round allocated to flow */ // unsigned quantum; /* Bytes per round allocated to flow */
// int perturb_period; /* Period of hash perturbation */ // int perturb_period; /* Period of hash perturbation */

View File

@ -308,13 +308,15 @@ func (qdisc *Fq) Type() string {
// FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair Queuing with the CoDel AQM scheme. // FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair Queuing with the CoDel AQM scheme.
type FqCodel struct { type FqCodel struct {
QdiscAttrs QdiscAttrs
Target uint32 Target uint32
Limit uint32 Limit uint32
Interval uint32 Interval uint32
ECN uint32 ECN uint32
Flows uint32 Flows uint32
Quantum uint32 Quantum uint32
// There are some more attributes here, but support for them seems not ubiquitous CEThreshold uint32
DropBatchSize uint32
MemoryLimit uint32
} }
func (fqcodel *FqCodel) String() string { func (fqcodel *FqCodel) String() string {

View File

@ -250,7 +250,15 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
if qdisc.Quantum > 0 { if qdisc.Quantum > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum)))) options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
} }
if qdisc.CEThreshold > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_CE_THRESHOLD, nl.Uint32Attr(qdisc.CEThreshold))
}
if qdisc.DropBatchSize > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_DROP_BATCH_SIZE, nl.Uint32Attr(qdisc.DropBatchSize))
}
if qdisc.MemoryLimit > 0 {
options.AddRtAttr(nl.TCA_FQ_CODEL_MEMORY_LIMIT, nl.Uint32Attr(qdisc.MemoryLimit))
}
case *Fq: case *Fq:
options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing)))) options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
@ -460,7 +468,6 @@ func parsePrioData(qdisc Qdisc, value []byte) error {
} }
func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error { func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
htb := qdisc.(*Htb) htb := qdisc.(*Htb)
for _, datum := range data { for _, datum := range data {
switch datum.Attr.Type { switch datum.Attr.Type {
@ -480,7 +487,6 @@ func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
} }
func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error { func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
fqCodel := qdisc.(*FqCodel) fqCodel := qdisc.(*FqCodel)
for _, datum := range data { for _, datum := range data {
@ -497,6 +503,12 @@ func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
fqCodel.Flows = native.Uint32(datum.Value) fqCodel.Flows = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_QUANTUM: case nl.TCA_FQ_CODEL_QUANTUM:
fqCodel.Quantum = native.Uint32(datum.Value) fqCodel.Quantum = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_CE_THRESHOLD:
fqCodel.CEThreshold = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_DROP_BATCH_SIZE:
fqCodel.DropBatchSize = native.Uint32(datum.Value)
case nl.TCA_FQ_CODEL_MEMORY_LIMIT:
fqCodel.MemoryLimit = native.Uint32(datum.Value)
} }
} }
return nil return nil
@ -504,13 +516,11 @@ func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
func parseHfscData(qdisc Qdisc, data []byte) error { func parseHfscData(qdisc Qdisc, data []byte) error {
Hfsc := qdisc.(*Hfsc) Hfsc := qdisc.(*Hfsc)
native = nl.NativeEndian()
Hfsc.Defcls = native.Uint16(data) Hfsc.Defcls = native.Uint16(data)
return nil return nil
} }
func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error { func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
fq := qdisc.(*Fq) fq := qdisc.(*Fq)
for _, datum := range data { for _, datum := range data {
switch datum.Attr.Type { switch datum.Attr.Type {
@ -575,7 +585,6 @@ func parseNetemData(qdisc Qdisc, value []byte) error {
} }
func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error { func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
tbf := qdisc.(*Tbf) tbf := qdisc.(*Tbf)
for _, datum := range data { for _, datum := range data {
switch datum.Attr.Type { switch datum.Attr.Type {

View File

@ -278,3 +278,54 @@ func (h *Handle) RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
return execRdmaSetLink(req) return execRdmaSetLink(req)
} }
// RdmaLinkDel deletes an rdma link
//
// Similar to: rdma link delete NAME
// REF: https://man7.org/linux/man-pages/man8/rdma-link.8.html
func RdmaLinkDel(name string) error {
return pkgHandle.RdmaLinkDel(name)
}
// RdmaLinkDel deletes an rdma link.
func (h *Handle) RdmaLinkDel(name string) error {
link, err := h.RdmaLinkByName(name)
if err != nil {
return err
}
proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_DELLINK)
req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
b := make([]byte, 4)
native.PutUint32(b, link.Attrs.Index)
req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b))
_, err = req.Execute(unix.NETLINK_RDMA, 0)
return err
}
// RdmaLinkAdd adds an rdma link for the specified type to the network device.
// Similar to: rdma link add NAME type TYPE netdev NETDEV
// NAME - specifies the new name of the rdma link to add
// TYPE - specifies which rdma type to use. Link types:
// rxe - Soft RoCE driver
// siw - Soft iWARP driver
// NETDEV - specifies the network device to which the link is bound
//
// REF: https://man7.org/linux/man-pages/man8/rdma-link.8.html
func RdmaLinkAdd(linkName, linkType, netdev string) error {
return pkgHandle.RdmaLinkAdd(linkName, linkType, netdev)
}
// RdmaLinkAdd adds an rdma link for the specified type to the network device.
func (h *Handle) RdmaLinkAdd(linkName string, linkType string, netdev string) error {
proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_NEWLINK)
req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, nl.ZeroTerminated(linkName)))
req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_LINK_TYPE, nl.ZeroTerminated(linkType)))
req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_NDEV_NAME, nl.ZeroTerminated(netdev)))
_, err := req.Execute(unix.NETLINK_RDMA, 0)
return err
}

View File

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

View File

@ -1,8 +1,11 @@
package netlink package netlink
import ( import (
"bytes"
"encoding/binary"
"fmt" "fmt"
"net" "net"
"strconv"
"strings" "strings"
"syscall" "syscall"
@ -21,6 +24,23 @@ const (
SCOPE_NOWHERE Scope = unix.RT_SCOPE_NOWHERE SCOPE_NOWHERE Scope = unix.RT_SCOPE_NOWHERE
) )
func (s Scope) String() string {
switch s {
case SCOPE_UNIVERSE:
return "universe"
case SCOPE_SITE:
return "site"
case SCOPE_LINK:
return "link"
case SCOPE_HOST:
return "host"
case SCOPE_NOWHERE:
return "nowhere"
default:
return "unknown"
}
}
const ( const (
RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota) RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota)
RT_FILTER_SCOPE RT_FILTER_SCOPE
@ -36,6 +56,7 @@ const (
RT_FILTER_PRIORITY RT_FILTER_PRIORITY
RT_FILTER_MARK RT_FILTER_MARK
RT_FILTER_MASK RT_FILTER_MASK
RT_FILTER_REALM
) )
const ( const (
@ -131,7 +152,6 @@ func (e *MPLSEncap) Decode(buf []byte) error {
if len(buf) < 4 { if len(buf) < 4 {
return fmt.Errorf("lack of bytes") return fmt.Errorf("lack of bytes")
} }
native := nl.NativeEndian()
l := native.Uint16(buf) l := native.Uint16(buf)
if len(buf) < int(l) { if len(buf) < int(l) {
return fmt.Errorf("lack of bytes") return fmt.Errorf("lack of bytes")
@ -147,7 +167,6 @@ func (e *MPLSEncap) Decode(buf []byte) error {
func (e *MPLSEncap) Encode() ([]byte, error) { func (e *MPLSEncap) Encode() ([]byte, error) {
s := nl.EncodeMPLSStack(e.Labels...) s := nl.EncodeMPLSStack(e.Labels...)
native := nl.NativeEndian()
hdr := make([]byte, 4) hdr := make([]byte, 4)
native.PutUint16(hdr, uint16(len(s)+4)) native.PutUint16(hdr, uint16(len(s)+4))
native.PutUint16(hdr[2:], nl.MPLS_IPTUNNEL_DST) native.PutUint16(hdr[2:], nl.MPLS_IPTUNNEL_DST)
@ -203,7 +222,6 @@ func (e *SEG6Encap) Decode(buf []byte) error {
if len(buf) < 4 { if len(buf) < 4 {
return fmt.Errorf("lack of bytes") return fmt.Errorf("lack of bytes")
} }
native := nl.NativeEndian()
// Get Length(l) & Type(typ) : 2 + 2 bytes // Get Length(l) & Type(typ) : 2 + 2 bytes
l := native.Uint16(buf) l := native.Uint16(buf)
if len(buf) < int(l) { if len(buf) < int(l) {
@ -223,7 +241,6 @@ func (e *SEG6Encap) Decode(buf []byte) error {
} }
func (e *SEG6Encap) Encode() ([]byte, error) { func (e *SEG6Encap) Encode() ([]byte, error) {
s, err := nl.EncodeSEG6Encap(e.Mode, e.Segments) s, err := nl.EncodeSEG6Encap(e.Mode, e.Segments)
native := nl.NativeEndian()
hdr := make([]byte, 4) hdr := make([]byte, 4)
native.PutUint16(hdr, uint16(len(s)+4)) native.PutUint16(hdr, uint16(len(s)+4))
native.PutUint16(hdr[2:], nl.SEG6_IPTUNNEL_SRH) native.PutUint16(hdr[2:], nl.SEG6_IPTUNNEL_SRH)
@ -233,7 +250,7 @@ func (e *SEG6Encap) String() string {
segs := make([]string, 0, len(e.Segments)) segs := make([]string, 0, len(e.Segments))
// append segment backwards (from n to 0) since seg#0 is the last segment. // append segment backwards (from n to 0) since seg#0 is the last segment.
for i := len(e.Segments); i > 0; i-- { for i := len(e.Segments); i > 0; i-- {
segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1])) segs = append(segs, e.Segments[i-1].String())
} }
str := fmt.Sprintf("mode %s segs %d [ %s ]", nl.SEG6EncapModeString(e.Mode), str := fmt.Sprintf("mode %s segs %d [ %s ]", nl.SEG6EncapModeString(e.Mode),
len(e.Segments), strings.Join(segs, " ")) len(e.Segments), strings.Join(segs, " "))
@ -284,7 +301,6 @@ func (e *SEG6LocalEncap) Decode(buf []byte) error {
if err != nil { if err != nil {
return err return err
} }
native := nl.NativeEndian()
for _, attr := range attrs { for _, attr := range attrs {
switch attr.Attr.Type { switch attr.Attr.Type {
case nl.SEG6_LOCAL_ACTION: case nl.SEG6_LOCAL_ACTION:
@ -314,7 +330,6 @@ func (e *SEG6LocalEncap) Decode(buf []byte) error {
} }
func (e *SEG6LocalEncap) Encode() ([]byte, error) { func (e *SEG6LocalEncap) Encode() ([]byte, error) {
var err error var err error
native := nl.NativeEndian()
res := make([]byte, 8) res := make([]byte, 8)
native.PutUint16(res, 8) // length native.PutUint16(res, 8) // length
native.PutUint16(res[2:], nl.SEG6_LOCAL_ACTION) native.PutUint16(res[2:], nl.SEG6_LOCAL_ACTION)
@ -405,7 +420,7 @@ func (e *SEG6LocalEncap) String() string {
segs := make([]string, 0, len(e.Segments)) segs := make([]string, 0, len(e.Segments))
//append segment backwards (from n to 0) since seg#0 is the last segment. //append segment backwards (from n to 0) since seg#0 is the last segment.
for i := len(e.Segments); i > 0; i-- { for i := len(e.Segments); i > 0; i-- {
segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1])) segs = append(segs, e.Segments[i-1].String())
} }
strs = append(strs, fmt.Sprintf("segs %d [ %s ]", len(e.Segments), strings.Join(segs, " "))) strs = append(strs, fmt.Sprintf("segs %d [ %s ]", len(e.Segments), strings.Join(segs, " ")))
} }
@ -446,6 +461,207 @@ func (e *SEG6LocalEncap) Equal(x Encap) bool {
return true return true
} }
// Encap BPF definitions
type bpfObj struct {
progFd int
progName string
}
type BpfEncap struct {
progs [nl.LWT_BPF_MAX]bpfObj
headroom int
}
// SetProg adds a bpf function to the route via netlink RTA_ENCAP. The fd must be a bpf
// program loaded with bpf(type=BPF_PROG_TYPE_LWT_*) matching the direction the program should
// be applied to (LWT_BPF_IN, LWT_BPF_OUT, LWT_BPF_XMIT).
func (e *BpfEncap) SetProg(mode, progFd int, progName string) error {
if progFd <= 0 {
return fmt.Errorf("lwt bpf SetProg: invalid fd")
}
if mode <= nl.LWT_BPF_UNSPEC || mode >= nl.LWT_BPF_XMIT_HEADROOM {
return fmt.Errorf("lwt bpf SetProg:invalid mode")
}
e.progs[mode].progFd = progFd
e.progs[mode].progName = fmt.Sprintf("%s[fd:%d]", progName, progFd)
return nil
}
// SetXmitHeadroom sets the xmit headroom (LWT_BPF_MAX_HEADROOM) via netlink RTA_ENCAP.
// maximum headroom is LWT_BPF_MAX_HEADROOM
func (e *BpfEncap) SetXmitHeadroom(headroom int) error {
if headroom > nl.LWT_BPF_MAX_HEADROOM || headroom < 0 {
return fmt.Errorf("invalid headroom size. range is 0 - %d", nl.LWT_BPF_MAX_HEADROOM)
}
e.headroom = headroom
return nil
}
func (e *BpfEncap) Type() int {
return nl.LWTUNNEL_ENCAP_BPF
}
func (e *BpfEncap) Decode(buf []byte) error {
if len(buf) < 4 {
return fmt.Errorf("lwt bpf decode: lack of bytes")
}
native := nl.NativeEndian()
attrs, err := nl.ParseRouteAttr(buf)
if err != nil {
return fmt.Errorf("lwt bpf decode: failed parsing attribute. err: %v", err)
}
for _, attr := range attrs {
if int(attr.Attr.Type) < 1 {
// nl.LWT_BPF_UNSPEC
continue
}
if int(attr.Attr.Type) > nl.LWT_BPF_MAX {
return fmt.Errorf("lwt bpf decode: received unknown attribute type: %d", attr.Attr.Type)
}
switch int(attr.Attr.Type) {
case nl.LWT_BPF_MAX_HEADROOM:
e.headroom = int(native.Uint32(attr.Value))
default:
bpfO := bpfObj{}
parsedAttrs, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return fmt.Errorf("lwt bpf decode: failed parsing route attribute")
}
for _, parsedAttr := range parsedAttrs {
switch int(parsedAttr.Attr.Type) {
case nl.LWT_BPF_PROG_FD:
bpfO.progFd = int(native.Uint32(parsedAttr.Value))
case nl.LWT_BPF_PROG_NAME:
bpfO.progName = string(parsedAttr.Value)
default:
return fmt.Errorf("lwt bpf decode: received unknown attribute: type: %d, len: %d", parsedAttr.Attr.Type, parsedAttr.Attr.Len)
}
}
e.progs[attr.Attr.Type] = bpfO
}
}
return nil
}
func (e *BpfEncap) Encode() ([]byte, error) {
buf := make([]byte, 0)
native = nl.NativeEndian()
for index, attr := range e.progs {
nlMsg := nl.NewRtAttr(index, []byte{})
if attr.progFd != 0 {
nlMsg.AddRtAttr(nl.LWT_BPF_PROG_FD, nl.Uint32Attr(uint32(attr.progFd)))
}
if attr.progName != "" {
nlMsg.AddRtAttr(nl.LWT_BPF_PROG_NAME, nl.ZeroTerminated(attr.progName))
}
if nlMsg.Len() > 4 {
buf = append(buf, nlMsg.Serialize()...)
}
}
if len(buf) <= 4 {
return nil, fmt.Errorf("lwt bpf encode: bpf obj definitions returned empty buffer")
}
if e.headroom > 0 {
hRoom := nl.NewRtAttr(nl.LWT_BPF_XMIT_HEADROOM, nl.Uint32Attr(uint32(e.headroom)))
buf = append(buf, hRoom.Serialize()...)
}
return buf, nil
}
func (e *BpfEncap) String() string {
progs := make([]string, 0)
for index, obj := range e.progs {
empty := bpfObj{}
switch index {
case nl.LWT_BPF_IN:
if obj != empty {
progs = append(progs, fmt.Sprintf("in: %s", obj.progName))
}
case nl.LWT_BPF_OUT:
if obj != empty {
progs = append(progs, fmt.Sprintf("out: %s", obj.progName))
}
case nl.LWT_BPF_XMIT:
if obj != empty {
progs = append(progs, fmt.Sprintf("xmit: %s", obj.progName))
}
}
}
if e.headroom > 0 {
progs = append(progs, fmt.Sprintf("xmit headroom: %d", e.headroom))
}
return strings.Join(progs, " ")
}
func (e *BpfEncap) Equal(x Encap) bool {
o, ok := x.(*BpfEncap)
if !ok {
return false
}
if e.headroom != o.headroom {
return false
}
for i := range o.progs {
if o.progs[i] != e.progs[i] {
return false
}
}
return true
}
type Via struct {
AddrFamily int
Addr net.IP
}
func (v *Via) Equal(x Destination) bool {
o, ok := x.(*Via)
if !ok {
return false
}
if v.AddrFamily == x.Family() && v.Addr.Equal(o.Addr) {
return true
}
return false
}
func (v *Via) String() string {
return fmt.Sprintf("Family: %d, Address: %s", v.AddrFamily, v.Addr.String())
}
func (v *Via) Family() int {
return v.AddrFamily
}
func (v *Via) Encode() ([]byte, error) {
buf := &bytes.Buffer{}
err := binary.Write(buf, native, uint16(v.AddrFamily))
if err != nil {
return nil, err
}
err = binary.Write(buf, native, v.Addr)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (v *Via) Decode(b []byte) error {
if len(b) < 6 {
return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b))
}
v.AddrFamily = int(native.Uint16(b[0:2]))
if v.AddrFamily == nl.FAMILY_V4 {
v.Addr = net.IP(b[2:6])
return nil
} else if v.AddrFamily == nl.FAMILY_V6 {
if len(b) < 18 {
return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b))
}
v.Addr = net.IP(b[2:])
return nil
}
return fmt.Errorf("decoding failed: address family %d unknown", v.AddrFamily)
}
// RouteAdd will add a route to the system. // RouteAdd will add a route to the system.
// Equivalent to: `ip route add $route` // Equivalent to: `ip route add $route`
func RouteAdd(route *Route) error { func RouteAdd(route *Route) error {
@ -460,6 +676,32 @@ func (h *Handle) RouteAdd(route *Route) error {
return h.routeHandle(route, req, nl.NewRtMsg()) return h.routeHandle(route, req, nl.NewRtMsg())
} }
// RouteAppend will append a route to the system.
// Equivalent to: `ip route append $route`
func RouteAppend(route *Route) error {
return pkgHandle.RouteAppend(route)
}
// RouteAppend will append a route to the system.
// Equivalent to: `ip route append $route`
func (h *Handle) RouteAppend(route *Route) error {
flags := unix.NLM_F_CREATE | unix.NLM_F_APPEND | unix.NLM_F_ACK
req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
}
// RouteAddEcmp will add a route to the system.
func RouteAddEcmp(route *Route) error {
return pkgHandle.RouteAddEcmp(route)
}
// RouteAddEcmp will add a route to the system.
func (h *Handle) RouteAddEcmp(route *Route) error {
flags := unix.NLM_F_CREATE | unix.NLM_F_ACK
req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
}
// RouteReplace will add a route to the system. // RouteReplace will add a route to the system.
// Equivalent to: `ip route replace $route` // Equivalent to: `ip route replace $route`
func RouteReplace(route *Route) error { func RouteReplace(route *Route) error {
@ -533,7 +775,13 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
if err != nil { if err != nil {
return err return err
} }
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP, buf)) switch route.Encap.Type() {
case nl.LWTUNNEL_ENCAP_BPF:
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP|unix.NLA_F_NESTED, buf))
default:
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP, buf))
}
} }
if route.Src != nil { if route.Src != nil {
@ -567,6 +815,14 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData))
} }
if route.Via != nil {
buf, err := route.Via.Encode()
if err != nil {
return fmt.Errorf("failed to encode RTA_VIA: %v", err)
}
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_VIA, buf))
}
if len(route.MultiPath) > 0 { if len(route.MultiPath) > 0 {
buf := []byte{} buf := []byte{}
for _, nh := range route.MultiPath { for _, nh := range route.MultiPath {
@ -609,6 +865,13 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
} }
children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf)) children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf))
} }
if nh.Via != nil {
buf, err := nh.Via.Encode()
if err != nil {
return err
}
children = append(children, nl.NewRtAttr(unix.RTA_VIA, buf))
}
rtnh.Children = children rtnh.Children = children
buf = append(buf, rtnh.Serialize()...) buf = append(buf, rtnh.Serialize()...)
} }
@ -631,6 +894,11 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
native.PutUint32(b, uint32(route.Priority)) native.PutUint32(b, uint32(route.Priority))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PRIORITY, b)) rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PRIORITY, b))
} }
if route.Realm > 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(route.Realm))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_FLOW, b))
}
if route.Tos > 0 { if route.Tos > 0 {
msg.Tos = uint8(route.Tos) msg.Tos = uint8(route.Tos)
} }
@ -723,10 +991,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
req.AddData(attr) req.AddData(attr)
} }
var ( b := make([]byte, 4)
b = make([]byte, 4)
native = nl.NativeEndian()
)
native.PutUint32(b, uint32(route.LinkIndex)) native.PutUint32(b, uint32(route.LinkIndex))
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b)) req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
@ -802,6 +1067,8 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
continue continue
case filterMask&RT_FILTER_TOS != 0 && route.Tos != filter.Tos: case filterMask&RT_FILTER_TOS != 0 && route.Tos != filter.Tos:
continue continue
case filterMask&RT_FILTER_REALM != 0 && route.Realm != filter.Realm:
continue
case filterMask&RT_FILTER_OIF != 0 && route.LinkIndex != filter.LinkIndex: case filterMask&RT_FILTER_OIF != 0 && route.LinkIndex != filter.LinkIndex:
continue continue
case filterMask&RT_FILTER_IIF != 0 && route.ILinkIndex != filter.ILinkIndex: case filterMask&RT_FILTER_IIF != 0 && route.ILinkIndex != filter.ILinkIndex:
@ -834,14 +1101,14 @@ func deserializeRoute(m []byte) (Route, error) {
} }
route := Route{ route := Route{
Scope: Scope(msg.Scope), Scope: Scope(msg.Scope),
Protocol: int(msg.Protocol), Protocol: RouteProtocol(int(msg.Protocol)),
Table: int(msg.Table), Table: int(msg.Table),
Type: int(msg.Type), Type: int(msg.Type),
Tos: int(msg.Tos), Tos: int(msg.Tos),
Flags: int(msg.Flags), Flags: int(msg.Flags),
Family: int(msg.Family),
} }
native := nl.NativeEndian()
var encap, encapType syscall.NetlinkRouteAttr var encap, encapType syscall.NetlinkRouteAttr
for _, attr := range attrs { for _, attr := range attrs {
switch attr.Attr.Type { switch attr.Attr.Type {
@ -868,6 +1135,8 @@ func deserializeRoute(m []byte) (Route, error) {
route.ILinkIndex = int(native.Uint32(attr.Value[0:4])) route.ILinkIndex = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_PRIORITY: case unix.RTA_PRIORITY:
route.Priority = int(native.Uint32(attr.Value[0:4])) route.Priority = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_FLOW:
route.Realm = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_TABLE: case unix.RTA_TABLE:
route.Table = int(native.Uint32(attr.Value[0:4])) route.Table = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_MULTIPATH: case unix.RTA_MULTIPATH:
@ -907,6 +1176,12 @@ func deserializeRoute(m []byte) (Route, error) {
encapType = attr encapType = attr
case unix.RTA_ENCAP: case unix.RTA_ENCAP:
encap = attr encap = attr
case unix.RTA_VIA:
d := &Via{}
if err := d.Decode(attr.Value); err != nil {
return nil, nil, err
}
info.Via = d
} }
} }
@ -944,6 +1219,12 @@ func deserializeRoute(m []byte) (Route, error) {
return route, err return route, err
} }
route.NewDst = d route.NewDst = d
case unix.RTA_VIA:
v := &Via{}
if err := v.Decode(attr.Value); err != nil {
return route, err
}
route.Via = v
case unix.RTA_ENCAP_TYPE: case unix.RTA_ENCAP_TYPE:
encapType = attr encapType = attr
case unix.RTA_ENCAP: case unix.RTA_ENCAP:
@ -1011,6 +1292,11 @@ func deserializeRoute(m []byte) (Route, error) {
if err := e.Decode(encap.Value); err != nil { if err := e.Decode(encap.Value); err != nil {
return route, err return route, err
} }
case nl.LWTUNNEL_ENCAP_BPF:
e = &BpfEncap{}
if err := e.Decode(encap.Value); err != nil {
return route, err
}
} }
route.Encap = e route.Encap = e
} }
@ -1021,7 +1307,10 @@ func deserializeRoute(m []byte) (Route, error) {
// RouteGetOptions contains a set of options to use with // RouteGetOptions contains a set of options to use with
// RouteGetWithOptions // RouteGetWithOptions
type RouteGetOptions struct { type RouteGetOptions struct {
Iif string
Oif string
VrfName string VrfName string
SrcAddr net.IP
} }
// RouteGetWithOptions gets a route to a specific destination from the host system. // RouteGetWithOptions gets a route to a specific destination from the host system.
@ -1053,23 +1342,61 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption
msg := &nl.RtMsg{} msg := &nl.RtMsg{}
msg.Family = uint8(family) msg.Family = uint8(family)
msg.Dst_len = bitlen msg.Dst_len = bitlen
if options != nil && options.SrcAddr != nil {
msg.Src_len = bitlen
}
msg.Flags = unix.RTM_F_LOOKUP_TABLE
req.AddData(msg) req.AddData(msg)
rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData) rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData)
req.AddData(rtaDst) req.AddData(rtaDst)
if options != nil { if options != nil {
link, err := LinkByName(options.VrfName) if options.VrfName != "" {
if err != nil { link, err := LinkByName(options.VrfName)
return nil, err if err != nil {
} return nil, err
var ( }
b = make([]byte, 4) b := make([]byte, 4)
native = nl.NativeEndian() native.PutUint32(b, uint32(link.Attrs().Index))
)
native.PutUint32(b, uint32(link.Attrs().Index))
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b)) req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
}
if len(options.Iif) > 0 {
link, err := LinkByName(options.Iif)
if err != nil {
return nil, err
}
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Attrs().Index))
req.AddData(nl.NewRtAttr(unix.RTA_IIF, b))
}
if len(options.Oif) > 0 {
link, err := LinkByName(options.Oif)
if err != nil {
return nil, err
}
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Attrs().Index))
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
}
if options.SrcAddr != nil {
var srcAddr []byte
if family == FAMILY_V4 {
srcAddr = options.SrcAddr.To4()
} else {
srcAddr = options.SrcAddr.To16()
}
req.AddData(nl.NewRtAttr(unix.RTA_SRC, srcAddr))
}
} }
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
@ -1151,7 +1478,8 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
msgs, from, err := s.Receive() msgs, from, err := s.Receive()
if err != nil { if err != nil {
if cberr != nil { if cberr != nil {
cberr(err) cberr(fmt.Errorf("Receive failed: %v",
err))
} }
return return
} }
@ -1166,22 +1494,22 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
continue continue
} }
if m.Header.Type == unix.NLMSG_ERROR { if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4])) error := int32(native.Uint32(m.Data[0:4]))
if error == 0 { if error == 0 {
continue continue
} }
if cberr != nil { if cberr != nil {
cberr(syscall.Errno(-error)) cberr(fmt.Errorf("error message: %v",
syscall.Errno(-error)))
} }
return continue
} }
route, err := deserializeRoute(m.Data) route, err := deserializeRoute(m.Data)
if err != nil { if err != nil {
if cberr != nil { if cberr != nil {
cberr(err) cberr(err)
} }
return continue
} }
ch <- RouteUpdate{Type: m.Header.Type, Route: route} ch <- RouteUpdate{Type: m.Header.Type, Route: route}
} }
@ -1190,3 +1518,54 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
return nil return nil
} }
func (p RouteProtocol) String() string {
switch int(p) {
case unix.RTPROT_BABEL:
return "babel"
case unix.RTPROT_BGP:
return "bgp"
case unix.RTPROT_BIRD:
return "bird"
case unix.RTPROT_BOOT:
return "boot"
case unix.RTPROT_DHCP:
return "dhcp"
case unix.RTPROT_DNROUTED:
return "dnrouted"
case unix.RTPROT_EIGRP:
return "eigrp"
case unix.RTPROT_GATED:
return "gated"
case unix.RTPROT_ISIS:
return "isis"
//case unix.RTPROT_KEEPALIVED:
// return "keepalived"
case unix.RTPROT_KERNEL:
return "kernel"
case unix.RTPROT_MROUTED:
return "mrouted"
case unix.RTPROT_MRT:
return "mrt"
case unix.RTPROT_NTK:
return "ntk"
case unix.RTPROT_OSPF:
return "ospf"
case unix.RTPROT_RA:
return "ra"
case unix.RTPROT_REDIRECT:
return "redirect"
case unix.RTPROT_RIP:
return "rip"
case unix.RTPROT_STATIC:
return "static"
case unix.RTPROT_UNSPEC:
return "unspec"
case unix.RTPROT_XORP:
return "xorp"
case unix.RTPROT_ZEBRA:
return "zebra"
default:
return strconv.Itoa(int(p))
}
}

View File

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

View File

@ -28,7 +28,18 @@ type Rule struct {
} }
func (r Rule) String() string { func (r Rule) String() string {
return fmt.Sprintf("ip rule %d: from %s table %d", r.Priority, r.Src, r.Table) from := "all"
if r.Src != nil && r.Src.String() != "<nil>" {
from = r.Src.String()
}
to := "all"
if r.Dst != nil && r.Dst.String() != "<nil>" {
to = r.Dst.String()
}
return fmt.Sprintf("ip rule %d: from %s to %s table %d",
r.Priority, from, to, r.Table)
} }
// NewRule return empty rules. // NewRule return empty rules.

View File

@ -97,8 +97,6 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
req.AddData(rtAttrs[i]) req.AddData(rtAttrs[i])
} }
native := nl.NativeEndian()
if rule.Priority >= 0 { if rule.Priority >= 0 {
b := make([]byte, 4) b := make([]byte, 4)
native.PutUint32(b, uint32(rule.Priority)) native.PutUint32(b, uint32(rule.Priority))
@ -199,7 +197,6 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
return nil, err return nil, err
} }
native := nl.NativeEndian()
var res = make([]Rule, 0) var res = make([]Rule, 0)
for i := range msgs { for i := range msgs {
msg := nl.DeserializeRtMsg(msgs[i]) msg := nl.DeserializeRtMsg(msgs[i])
@ -232,7 +229,7 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
case nl.FRA_FWMASK: case nl.FRA_FWMASK:
rule.Mask = int(native.Uint32(attrs[j].Value[0:4])) rule.Mask = int(native.Uint32(attrs[j].Value[0:4]))
case nl.FRA_TUN_ID: case nl.FRA_TUN_ID:
rule.TunID = uint(native.Uint64(attrs[j].Value[0:4])) rule.TunID = uint(native.Uint64(attrs[j].Value[0:8]))
case nl.FRA_IIFNAME: case nl.FRA_IIFNAME:
rule.IifName = string(attrs[j].Value[:len(attrs[j].Value)-1]) rule.IifName = string(attrs[j].Value[:len(attrs[j].Value)-1])
case nl.FRA_OIFNAME: case nl.FRA_OIFNAME:

View File

@ -172,35 +172,78 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
return sock, nil return sock, nil
} }
// SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type. // SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info.
func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) { func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
s, err := nl.Subscribe(unix.NETLINK_INET_DIAG) var result []*InetDiagTCPInfoResp
err := socketDiagTCPExecutor(family, func(m syscall.NetlinkMessage) error {
sockInfo := &Socket{}
if err := sockInfo.deserialize(m.Data); err != nil {
return err
}
attrs, err := nl.ParseRouteAttr(m.Data[sizeofSocket:])
if err != nil {
return err
}
res, err := attrsToInetDiagTCPInfoResp(attrs, sockInfo)
if err != nil {
return err
}
result = append(result, res)
return nil
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return result, nil
}
// SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket.
func SocketDiagTCP(family uint8) ([]*Socket, error) {
var result []*Socket
err := socketDiagTCPExecutor(family, func(m syscall.NetlinkMessage) error {
sockInfo := &Socket{}
if err := sockInfo.deserialize(m.Data); err != nil {
return err
}
result = append(result, sockInfo)
return nil
})
if err != nil {
return nil, err
}
return result, nil
}
// socketDiagTCPExecutor requests INET_DIAG_INFO for TCP protocol for specified family type.
func socketDiagTCPExecutor(family uint8, receiver func(syscall.NetlinkMessage) error) error {
s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
if err != nil {
return err
}
defer s.Close() defer s.Close()
req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP) req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
req.AddData(&socketRequest{ req.AddData(&socketRequest{
Family: family, Family: family,
Protocol: unix.IPPROTO_TCP, Protocol: unix.IPPROTO_TCP,
Ext: INET_DIAG_INFO, Ext: (1 << (INET_DIAG_VEGASINFO - 1)) | (1 << (INET_DIAG_INFO - 1)),
States: uint32(0xfff), // All TCP states States: uint32(0xfff), // All TCP states
}) })
s.Send(req) s.Send(req)
var result []*InetDiagTCPInfoResp
loop: loop:
for { for {
msgs, from, err := s.Receive() msgs, from, err := s.Receive()
if err != nil { if err != nil {
return nil, err return err
} }
if from.Pid != nl.PidKernel { if from.Pid != nl.PidKernel {
return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel) return fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
} }
if len(msgs) == 0 { if len(msgs) == 0 {
return nil, errors.New("no message nor error from netlink") return errors.New("no message nor error from netlink")
} }
for _, m := range msgs { for _, m := range msgs {
@ -208,31 +251,41 @@ loop:
case unix.NLMSG_DONE: case unix.NLMSG_DONE:
break loop break loop
case unix.NLMSG_ERROR: case unix.NLMSG_ERROR:
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4])) error := int32(native.Uint32(m.Data[0:4]))
return nil, syscall.Errno(-error) return syscall.Errno(-error)
} }
sockInfo := &Socket{} if err := receiver(m); err != nil {
if err := sockInfo.deserialize(m.Data); err != nil { return err
return nil, err
} }
attrs, err := nl.ParseRouteAttr(m.Data[sizeofSocket:])
if err != nil {
return nil, err
}
var tcpInfo *TCPInfo
for _, a := range attrs {
if a.Attr.Type == INET_DIAG_INFO {
tcpInfo = &TCPInfo{}
if err := tcpInfo.deserialize(a.Value); err != nil {
return nil, err
}
break
}
}
r := &InetDiagTCPInfoResp{InetDiagMsg: sockInfo, TCPInfo: tcpInfo}
result = append(result, r)
} }
} }
return result, nil return nil
}
func attrsToInetDiagTCPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagTCPInfoResp, error) {
var tcpInfo *TCPInfo
var tcpBBRInfo *TCPBBRInfo
for _, a := range attrs {
if a.Attr.Type == INET_DIAG_INFO {
tcpInfo = &TCPInfo{}
if err := tcpInfo.deserialize(a.Value); err != nil {
return nil, err
}
continue
}
if a.Attr.Type == INET_DIAG_BBRINFO {
tcpBBRInfo = &TCPBBRInfo{}
if err := tcpBBRInfo.deserialize(a.Value); err != nil {
return nil, err
}
continue
}
}
return &InetDiagTCPInfoResp{
InetDiagMsg: sockInfo,
TCPInfo: tcpInfo,
TCPBBRInfo: tcpBBRInfo,
}, nil
} }

View File

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

View File

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

View File

@ -58,12 +58,13 @@ func (a PolicyAction) String() string {
// policy. These rules are matched with XfrmState to determine encryption // policy. These rules are matched with XfrmState to determine encryption
// and authentication algorithms. // and authentication algorithms.
type XfrmPolicyTmpl struct { type XfrmPolicyTmpl struct {
Dst net.IP Dst net.IP
Src net.IP Src net.IP
Proto Proto Proto Proto
Mode Mode Mode Mode
Spi int Spi int
Reqid int Reqid int
Optional int
} }
func (t XfrmPolicyTmpl) String() string { func (t XfrmPolicyTmpl) String() string {

View File

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

View File

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

View File

@ -111,7 +111,7 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
// A state with spi 0 can't be deleted so don't allow it to be set // A state with spi 0 can't be deleted so don't allow it to be set
if state.Spi == 0 { if state.Spi == 0 {
return fmt.Errorf("Spi must be set when adding xfrm state.") return fmt.Errorf("Spi must be set when adding xfrm state")
} }
req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK) req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
@ -158,9 +158,13 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow)) out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow))
req.AddData(out) req.AddData(out)
} }
if state.OutputMark != 0 { if state.OutputMark != nil {
out := nl.NewRtAttr(nl.XFRMA_OUTPUT_MARK, nl.Uint32Attr(uint32(state.OutputMark))) out := nl.NewRtAttr(nl.XFRMA_SET_MARK, nl.Uint32Attr(state.OutputMark.Value))
req.AddData(out) req.AddData(out)
if state.OutputMark.Mask != 0 {
out = nl.NewRtAttr(nl.XFRMA_SET_MARK_MASK, nl.Uint32Attr(state.OutputMark.Mask))
req.AddData(out)
}
} }
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid))) ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
@ -377,8 +381,19 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
state.Mark = new(XfrmMark) state.Mark = new(XfrmMark)
state.Mark.Value = mark.Value state.Mark.Value = mark.Value
state.Mark.Mask = mark.Mask state.Mark.Mask = mark.Mask
case nl.XFRMA_OUTPUT_MARK: case nl.XFRMA_SET_MARK:
state.OutputMark = int(native.Uint32(attr.Value)) if state.OutputMark == nil {
state.OutputMark = new(XfrmMark)
}
state.OutputMark.Value = native.Uint32(attr.Value)
case nl.XFRMA_SET_MARK_MASK:
if state.OutputMark == nil {
state.OutputMark = new(XfrmMark)
}
state.OutputMark.Mask = native.Uint32(attr.Value)
if state.OutputMark.Mask == 0xffffffff {
state.OutputMark.Mask = 0
}
case nl.XFRMA_IF_ID: case nl.XFRMA_IF_ID:
state.Ifid = int(native.Uint32(attr.Value)) state.Ifid = int(native.Uint32(attr.Value))
} }

View File

@ -256,7 +256,7 @@ github.com/stretchr/testify/assert
# github.com/urfave/cli v1.22.2 # github.com/urfave/cli v1.22.2
## explicit ## explicit
github.com/urfave/cli github.com/urfave/cli
# github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 # github.com/vishvananda/netlink v1.1.1-0.20210924202909-187053b97868
## explicit ## explicit
github.com/vishvananda/netlink github.com/vishvananda/netlink
github.com/vishvananda/netlink/nl github.com/vishvananda/netlink/nl

View File

@ -575,7 +575,7 @@ func tapNetworkPair(ctx context.Context, endpoint Endpoint, queues int, disableV
if err != nil { if err != nil {
return err return err
} }
defer netHandle.Delete() defer netHandle.Close()
netPair := endpoint.NetworkPair() netPair := endpoint.NetworkPair()
@ -672,7 +672,7 @@ func setupTCFiltering(ctx context.Context, endpoint Endpoint, queues int, disabl
if err != nil { if err != nil {
return err return err
} }
defer netHandle.Delete() defer netHandle.Close()
netPair := endpoint.NetworkPair() netPair := endpoint.NetworkPair()
@ -847,7 +847,7 @@ func untapNetworkPair(ctx context.Context, endpoint Endpoint) error {
if err != nil { if err != nil {
return err return err
} }
defer netHandle.Delete() defer netHandle.Close()
netPair := endpoint.NetworkPair() netPair := endpoint.NetworkPair()
@ -891,7 +891,7 @@ func removeTCFiltering(ctx context.Context, endpoint Endpoint) error {
if err != nil { if err != nil {
return err return err
} }
defer netHandle.Delete() defer netHandle.Close()
netPair := endpoint.NetworkPair() netPair := endpoint.NetworkPair()
@ -1048,6 +1048,7 @@ func generateVCNetworkStructures(ctx context.Context, networkNS NetworkNamespace
r.Device = endpoint.Name() r.Device = endpoint.Name()
r.Scope = uint32(route.Scope) r.Scope = uint32(route.Scope)
r.Family = utils.ConvertNetlinkFamily((int32)(route.Family))
routes = append(routes, &r) routes = append(routes, &r)
} }
@ -1168,7 +1169,7 @@ func createEndpointsFromScan(networkNSPath string, config *NetworkConfig) ([]End
if err != nil { if err != nil {
return []Endpoint{}, err return []Endpoint{}, err
} }
defer netlinkHandle.Delete() defer netlinkHandle.Close()
linkList, err := netlinkHandle.LinkList() linkList, err := netlinkHandle.LinkList()
if err != nil { if err != nil {
@ -1568,7 +1569,7 @@ func addIFBDevice() (int, error) {
if err != nil { if err != nil {
return -1, err return -1, err
} }
defer netHandle.Delete() defer netHandle.Close()
// There exists error when using netlink library to create ifb interface // There exists error when using netlink library to create ifb interface
cmd := exec.Command("ip", "link", "add", "dev", "ifb0", "type", "ifb") cmd := exec.Command("ip", "link", "add", "dev", "ifb0", "type", "ifb")
@ -1744,7 +1745,7 @@ func removeTxRateLimiter(endpoint Endpoint, networkNSPath string) error {
if err != nil { if err != nil {
return err return err
} }
defer netHandle.Delete() defer netHandle.Close()
// remove ifb interface // remove ifb interface
ifbLink, err := netlink.LinkByName("ifb0") ifbLink, err := netlink.LinkByName("ifb0")

View File

@ -188,7 +188,8 @@ func TestCreateGetTunTapLink(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
netHandle, err := netlink.NewHandle() netHandle, err := netlink.NewHandle()
defer netHandle.Delete() assert.NoError(err)
defer netHandle.Close()
assert.NoError(err) assert.NoError(err)
@ -213,7 +214,8 @@ func TestCreateMacVtap(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
netHandle, err := netlink.NewHandle() netHandle, err := netlink.NewHandle()
defer netHandle.Delete() assert.NoError(err)
defer netHandle.Close()
assert.NoError(err) assert.NoError(err)
@ -258,7 +260,7 @@ func TestTcRedirectNetwork(t *testing.T) {
netHandle, err := netlink.NewHandle() netHandle, err := netlink.NewHandle()
assert.NoError(err) assert.NoError(err)
defer netHandle.Delete() defer netHandle.Close()
// Create a test veth interface. // Create a test veth interface.
vethName := "foo" vethName := "foo"
@ -296,7 +298,7 @@ func TestRxRateLimiter(t *testing.T) {
netHandle, err := netlink.NewHandle() netHandle, err := netlink.NewHandle()
assert.NoError(err) assert.NoError(err)
defer netHandle.Delete() defer netHandle.Close()
// Create a test veth interface. // Create a test veth interface.
vethName := "foo" vethName := "foo"
@ -345,7 +347,7 @@ func TestTxRateLimiter(t *testing.T) {
netHandle, err := netlink.NewHandle() netHandle, err := netlink.NewHandle()
assert.NoError(err) assert.NoError(err)
defer netHandle.Delete() defer netHandle.Close()
// Create a test veth interface. // Create a test veth interface.
vethName := "foo" vethName := "foo"

View File

@ -77,7 +77,7 @@ func TestIsPhysicalIface(t *testing.T) {
netlinkHandle, err := netlink.NewHandleAt(netnsHandle) netlinkHandle, err := netlink.NewHandleAt(netnsHandle)
assert.NoError(err) assert.NoError(err)
defer netlinkHandle.Delete() defer netlinkHandle.Close()
err = netlinkHandle.LinkAdd(link) err = netlinkHandle.LinkAdd(link)
assert.NoError(err) assert.NoError(err)

View File

@ -732,7 +732,10 @@ func (m *CheckRequest) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthHealth
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthHealth return ErrInvalidLengthHealth
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -802,7 +805,10 @@ func (m *HealthCheckResponse) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthHealth
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthHealth return ErrInvalidLengthHealth
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -917,7 +923,10 @@ func (m *VersionCheckResponse) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthHealth
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthHealth return ErrInvalidLengthHealth
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {

View File

@ -7717,7 +7717,7 @@ func (m *Spec) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > postIndex { if (iNdEx + skippy) > postIndex {
@ -7842,7 +7842,10 @@ func (m *Spec) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -8251,7 +8254,10 @@ func (m *Process) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -8340,7 +8346,10 @@ func (m *Box) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -8537,7 +8546,10 @@ func (m *User) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -8748,7 +8760,10 @@ func (m *LinuxCapabilities) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -8869,7 +8884,10 @@ func (m *POSIXRlimit) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -9048,7 +9066,10 @@ func (m *Mount) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -9151,7 +9172,10 @@ func (m *Root) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -9304,7 +9328,10 @@ func (m *Hooks) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -9470,7 +9497,10 @@ func (m *Hook) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -9699,7 +9729,7 @@ func (m *Linux) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > postIndex { if (iNdEx + skippy) > postIndex {
@ -10052,7 +10082,10 @@ func (m *Linux) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -10135,7 +10168,10 @@ func (m *Windows) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -10218,7 +10254,10 @@ func (m *Solaris) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -10326,7 +10365,10 @@ func (m *LinuxIDMapping) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -10441,7 +10483,10 @@ func (m *LinuxNamespace) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -10651,7 +10696,10 @@ func (m *LinuxDevice) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -10950,7 +10998,10 @@ func (m *LinuxResources) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -11135,7 +11186,10 @@ func (m *LinuxMemory) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -11345,7 +11399,10 @@ func (m *LinuxCPU) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -11472,7 +11529,10 @@ func (m *LinuxWeightDevice) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -11580,7 +11640,10 @@ func (m *LinuxThrottleDevice) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -11839,7 +11902,10 @@ func (m *LinuxBlockIO) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -11909,7 +11975,10 @@ func (m *LinuxPids) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -12082,7 +12151,10 @@ func (m *LinuxDeviceCgroup) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -12186,7 +12258,10 @@ func (m *LinuxNetwork) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -12288,7 +12363,10 @@ func (m *LinuxHugepageLimit) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -12390,7 +12468,10 @@ func (m *LinuxInterfacePriority) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -12571,7 +12652,10 @@ func (m *LinuxSeccomp) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -12711,7 +12795,10 @@ func (m *LinuxSeccompArg) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -12880,7 +12967,10 @@ func (m *LinuxSyscall) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -12963,7 +13053,10 @@ func (m *LinuxIntelRdt) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthOci
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthOci return ErrInvalidLengthOci
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {

View File

@ -147,6 +147,7 @@ type Route struct {
Device string `protobuf:"bytes,3,opt,name=device,proto3" json:"device,omitempty"` Device string `protobuf:"bytes,3,opt,name=device,proto3" json:"device,omitempty"`
Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"` Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"`
Scope uint32 `protobuf:"varint,5,opt,name=scope,proto3" json:"scope,omitempty"` Scope uint32 `protobuf:"varint,5,opt,name=scope,proto3" json:"scope,omitempty"`
Family IPFamily `protobuf:"varint,6,opt,name=family,proto3,enum=types.IPFamily" json:"family,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -240,37 +241,37 @@ func init() {
} }
var fileDescriptor_b0c68e5b9fabcd81 = []byte{ var fileDescriptor_b0c68e5b9fabcd81 = []byte{
// 472 bytes of a gzipped FileDescriptorProto // 479 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x31, 0x8f, 0xd3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x31, 0x8f, 0xd3, 0x30,
0x18, 0x86, 0xeb, 0xa6, 0xc9, 0x35, 0xae, 0x0e, 0x2a, 0x0b, 0x9d, 0x2c, 0x90, 0xa2, 0xa8, 0x0b, 0x18, 0x86, 0xeb, 0xa6, 0xc9, 0x35, 0xae, 0x0e, 0x2a, 0x0b, 0x9d, 0x2c, 0x90, 0xa2, 0xa8, 0x0b,
0x11, 0x12, 0x8d, 0x54, 0x10, 0xfb, 0x31, 0x9c, 0xd4, 0x05, 0x15, 0x6f, 0xb0, 0x20, 0xd7, 0x75, 0x11, 0x12, 0x8d, 0x54, 0x10, 0xfb, 0x31, 0x9c, 0xd4, 0x05, 0x15, 0x6f, 0xb0, 0x20, 0xd7, 0x75,
0xd3, 0xa8, 0x49, 0x1c, 0xd9, 0x4e, 0xab, 0x8a, 0x85, 0x3f, 0xc2, 0xff, 0xb9, 0x91, 0x91, 0xf1, 0xd3, 0xa8, 0x49, 0x1c, 0xd9, 0x4e, 0xab, 0x6e, 0xfc, 0x11, 0x36, 0x7e, 0xcc, 0x8d, 0x8c, 0x8c,
0xae, 0xbf, 0x04, 0xd9, 0x4e, 0xab, 0x50, 0x58, 0x6e, 0xca, 0xfb, 0x7c, 0xb6, 0xf3, 0xbd, 0xdf, 0x77, 0xfd, 0x25, 0xc8, 0x76, 0x5a, 0x85, 0x82, 0x90, 0x98, 0xfa, 0x3d, 0x9f, 0xed, 0x7e, 0xef,
0x1b, 0x07, 0x7e, 0xce, 0x72, 0xbd, 0x69, 0x96, 0x53, 0x26, 0xca, 0x74, 0x4b, 0x35, 0x7d, 0xcb, 0xfb, 0x3a, 0x86, 0x1f, 0xb3, 0x5c, 0x6f, 0x9a, 0xe5, 0x94, 0x89, 0x32, 0xdd, 0x52, 0x4d, 0x5f,
0x44, 0xa5, 0x69, 0x5e, 0x71, 0xa9, 0xfe, 0x61, 0x25, 0x59, 0x4a, 0x33, 0x5e, 0xe9, 0xb4, 0x96, 0x33, 0x51, 0x69, 0x9a, 0x57, 0x5c, 0xaa, 0x3f, 0x58, 0x49, 0x96, 0xd2, 0x8c, 0x57, 0x3a, 0xad,
0x42, 0x0b, 0x26, 0x0a, 0xe5, 0x94, 0x4a, 0xf5, 0xa1, 0xe6, 0x6a, 0x6a, 0x01, 0xf9, 0x16, 0x26, 0xa5, 0xd0, 0x82, 0x89, 0x42, 0xb9, 0x4a, 0xa5, 0xfa, 0x50, 0x73, 0x35, 0xb5, 0x80, 0x7c, 0x0b,
0x4b, 0x18, 0xce, 0x17, 0xb7, 0xab, 0x95, 0xe4, 0x4a, 0xa1, 0xd7, 0x30, 0x58, 0xd3, 0x32, 0x2f, 0x93, 0x25, 0x0c, 0xe7, 0x8b, 0xdb, 0xd5, 0x4a, 0x72, 0xa5, 0xd0, 0x4b, 0x18, 0xac, 0x69, 0x99,
0x0e, 0x18, 0xc4, 0x20, 0x79, 0x36, 0x7b, 0x3e, 0x75, 0x27, 0xe6, 0x8b, 0x3b, 0x5b, 0x26, 0xed, 0x17, 0x07, 0x0c, 0x62, 0x90, 0x3c, 0x99, 0x3d, 0x9d, 0xba, 0x13, 0xf3, 0xc5, 0x9d, 0x6d, 0x93,
0x32, 0xc2, 0xf0, 0x8a, 0xba, 0x33, 0xb8, 0x1f, 0x83, 0x24, 0x24, 0x27, 0x44, 0x08, 0x0e, 0x4a, 0x76, 0x19, 0x61, 0x78, 0x45, 0xdd, 0x19, 0xdc, 0x8f, 0x41, 0x12, 0x92, 0x13, 0x22, 0x04, 0x07,
0xaa, 0xb6, 0xd8, 0xb3, 0x65, 0xab, 0x27, 0x0f, 0x00, 0x86, 0xf3, 0x4a, 0x73, 0xb9, 0xa6, 0x8c, 0x25, 0x55, 0x5b, 0xec, 0xd9, 0xb6, 0xad, 0x27, 0x0f, 0x00, 0x86, 0xf3, 0x4a, 0x73, 0xb9, 0xa6,
0xa3, 0x1b, 0x18, 0xac, 0xf8, 0x2e, 0x67, 0xdc, 0x36, 0x09, 0x49, 0x4b, 0xe6, 0x64, 0x45, 0x4b, 0x8c, 0xa3, 0x1b, 0x18, 0xac, 0xf8, 0x2e, 0x67, 0xdc, 0x0e, 0x09, 0x49, 0x4b, 0xe6, 0x64, 0x45,
0xde, 0xbe, 0xd0, 0x6a, 0x34, 0x83, 0xa3, 0xb3, 0x3b, 0xae, 0xb0, 0x17, 0x7b, 0xc9, 0x68, 0x36, 0x4b, 0xde, 0xfe, 0xa1, 0xad, 0xd1, 0x0c, 0x8e, 0xce, 0xea, 0xb8, 0xc2, 0x5e, 0xec, 0x25, 0xa3,
0x3e, 0xbb, 0x6a, 0x57, 0x48, 0x77, 0x13, 0x1a, 0x43, 0xaf, 0xd4, 0x0d, 0x1e, 0xc4, 0x20, 0x19, 0xd9, 0xf8, 0xac, 0xaa, 0x5d, 0x21, 0xdd, 0x4d, 0x68, 0x0c, 0xbd, 0x52, 0x37, 0x78, 0x10, 0x83,
0x10, 0x23, 0x4d, 0xc7, 0xcd, 0xde, 0x6c, 0xc0, 0xbe, 0xeb, 0xe8, 0xc8, 0x4c, 0x51, 0xb3, 0x7c, 0x64, 0x40, 0x4c, 0x69, 0x26, 0x6e, 0xf6, 0x66, 0x03, 0xf6, 0xdd, 0x44, 0x47, 0xc6, 0x45, 0xcd,
0x41, 0xf5, 0x06, 0x07, 0x6e, 0x8a, 0x16, 0x8d, 0x17, 0xd3, 0x03, 0x5f, 0x39, 0x2f, 0x46, 0xa3, 0xf2, 0x05, 0xd5, 0x1b, 0x1c, 0x38, 0x17, 0x2d, 0x1a, 0x2d, 0x66, 0x06, 0xbe, 0x72, 0x5a, 0x4c,
0x57, 0x30, 0x94, 0x74, 0xff, 0x6d, 0x5d, 0xd0, 0x4c, 0xe1, 0x61, 0x0c, 0x92, 0x6b, 0x32, 0x94, 0x8d, 0x5e, 0xc0, 0x50, 0xd2, 0xfd, 0x97, 0x75, 0x41, 0x33, 0x85, 0x87, 0x31, 0x48, 0xae, 0xc9,
0x74, 0x7f, 0x67, 0x78, 0xf2, 0x1d, 0xfa, 0x44, 0x34, 0xda, 0x4e, 0xb1, 0xe2, 0x4a, 0xb7, 0xb3, 0x50, 0xd2, 0xfd, 0x9d, 0xe1, 0xc9, 0x77, 0x00, 0x7d, 0x22, 0x1a, 0x6d, 0x6d, 0xac, 0xb8, 0xd2,
0x59, 0x6d, 0xfa, 0x64, 0x54, 0xf3, 0x3d, 0x3d, 0x9c, 0xd2, 0x6a, 0xb1, 0x93, 0x85, 0xf7, 0x57, 0xad, 0x39, 0x5b, 0x9b, 0x41, 0x19, 0xd5, 0x7c, 0x4f, 0x0f, 0xa7, 0xb8, 0x5a, 0xec, 0x84, 0xe1,
0x16, 0x37, 0x30, 0x50, 0xa2, 0x91, 0x8c, 0xdb, 0x31, 0x42, 0xd2, 0x12, 0x7a, 0x01, 0x7d, 0xc5, 0xfd, 0x16, 0xc6, 0x0d, 0x0c, 0x94, 0x68, 0x24, 0xe3, 0xd6, 0x47, 0x48, 0x5a, 0x42, 0xcf, 0xa0,
0x44, 0xcd, 0xed, 0x20, 0xd7, 0xc4, 0xc1, 0xe4, 0x27, 0x80, 0xa3, 0x5b, 0xb2, 0xf8, 0xc4, 0xf3, 0xaf, 0x98, 0xa8, 0xb9, 0x75, 0x72, 0x4d, 0x1c, 0x74, 0xee, 0x2d, 0xf8, 0xe7, 0xbd, 0x4d, 0xbe,
0x6c, 0xb3, 0x14, 0xd2, 0xa4, 0xa6, 0xc5, 0x39, 0x12, 0x6b, 0xe5, 0xbf, 0xa9, 0x75, 0x36, 0x75, 0x01, 0x38, 0xba, 0x25, 0x8b, 0x0f, 0x3c, 0xcf, 0x36, 0x4b, 0x21, 0x4d, 0xbe, 0x5a, 0x9c, 0xc3,
0x9c, 0xf4, 0x2f, 0x9d, 0x14, 0x85, 0xf9, 0xb8, 0x27, 0x87, 0x8e, 0xac, 0x13, 0x4d, 0xb5, 0x33, 0xb3, 0x9a, 0xff, 0x9a, 0x6f, 0x67, 0x53, 0x47, 0x72, 0xff, 0x52, 0x72, 0x51, 0x98, 0xcf, 0xe0,
0xe8, 0x13, 0x07, 0xa6, 0xea, 0xf2, 0xf1, 0x5d, 0xd5, 0xc2, 0x9b, 0x97, 0x70, 0x78, 0xba, 0x41, 0x64, 0xc5, 0x91, 0x95, 0xac, 0xa9, 0x76, 0x4e, 0x7c, 0xe2, 0xc0, 0x74, 0x5d, 0x92, 0xbe, 0xeb,
0x28, 0x80, 0xfd, 0xdd, 0xfb, 0x71, 0xcf, 0x3e, 0x3f, 0x8c, 0xc1, 0x47, 0x75, 0xff, 0x18, 0xf5, 0x5a, 0x78, 0xf5, 0x1c, 0x0e, 0x4f, 0x9a, 0x51, 0x00, 0xfb, 0xbb, 0xb7, 0xe3, 0x9e, 0xfd, 0x7d,
0x7e, 0x3f, 0x46, 0xbd, 0x1f, 0xc7, 0x08, 0xdc, 0x1f, 0x23, 0xf0, 0xeb, 0x18, 0x81, 0x87, 0x63, 0x37, 0x06, 0xef, 0xd5, 0xfd, 0x63, 0xd4, 0xfb, 0xf9, 0x18, 0xf5, 0xbe, 0x1e, 0x23, 0x70, 0x7f,
0x04, 0xbe, 0x7e, 0x79, 0xe2, 0x9d, 0x97, 0x4d, 0xa5, 0xf3, 0x92, 0xa7, 0xbb, 0x5c, 0xea, 0xce, 0x8c, 0xc0, 0x8f, 0x63, 0x04, 0x1e, 0x8e, 0x11, 0xf8, 0xfc, 0xe9, 0x3f, 0x5f, 0x87, 0x6c, 0x2a,
0x52, 0xbd, 0xcd, 0x2e, 0x7f, 0x87, 0x65, 0x60, 0xe5, 0xbb, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x97, 0x3c, 0xdd, 0xe5, 0x52, 0x77, 0x96, 0xea, 0x6d, 0x76, 0xf9, 0x70, 0x96, 0x81, 0x2d,
0xed, 0x3e, 0x9a, 0x58, 0x57, 0x03, 0x00, 0x00, 0xdf, 0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x21, 0x00, 0xa1, 0xc2, 0x81, 0x03, 0x00, 0x00,
} }
func (m *IPAddress) Marshal() (dAtA []byte, err error) { func (m *IPAddress) Marshal() (dAtA []byte, err error) {
@ -429,6 +430,11 @@ func (m *Route) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized) i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized)
} }
if m.Family != 0 {
i = encodeVarintTypes(dAtA, i, uint64(m.Family))
i--
dAtA[i] = 0x30
}
if m.Scope != 0 { if m.Scope != 0 {
i = encodeVarintTypes(dAtA, i, uint64(m.Scope)) i = encodeVarintTypes(dAtA, i, uint64(m.Scope))
i-- i--
@ -631,6 +637,9 @@ func (m *Route) Size() (n int) {
if m.Scope != 0 { if m.Scope != 0 {
n += 1 + sovTypes(uint64(m.Scope)) n += 1 + sovTypes(uint64(m.Scope))
} }
if m.Family != 0 {
n += 1 + sovTypes(uint64(m.Family))
}
if m.XXX_unrecognized != nil { if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized) n += len(m.XXX_unrecognized)
} }
@ -719,6 +728,7 @@ func (this *Route) String() string {
`Device:` + fmt.Sprintf("%v", this.Device) + `,`, `Device:` + fmt.Sprintf("%v", this.Device) + `,`,
`Source:` + fmt.Sprintf("%v", this.Source) + `,`, `Source:` + fmt.Sprintf("%v", this.Source) + `,`,
`Scope:` + fmt.Sprintf("%v", this.Scope) + `,`, `Scope:` + fmt.Sprintf("%v", this.Scope) + `,`,
`Family:` + fmt.Sprintf("%v", this.Family) + `,`,
`XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`,
`}`, `}`,
}, "") }, "")
@ -865,7 +875,10 @@ func (m *IPAddress) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes return ErrInvalidLengthTypes
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -1148,7 +1161,10 @@ func (m *Interface) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes return ErrInvalidLengthTypes
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -1340,13 +1356,35 @@ func (m *Route) Unmarshal(dAtA []byte) error {
break break
} }
} }
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Family", wireType)
}
m.Family = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Family |= IPFamily(b&0x7F) << shift
if b < 0x80 {
break
}
}
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:]) skippy, err := skipTypes(dAtA[iNdEx:])
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes return ErrInvalidLengthTypes
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
@ -1535,7 +1573,10 @@ func (m *ARPNeighbor) Unmarshal(dAtA []byte) error {
if err != nil { if err != nil {
return err return err
} }
if (skippy < 0) || (iNdEx+skippy) < 0 { if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes return ErrInvalidLengthTypes
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {

View File

@ -156,7 +156,7 @@ func tapNetwork(endpoint *TapEndpoint, numCPUs uint32, disableVhostNet bool) err
if err != nil { if err != nil {
return err return err
} }
defer netHandle.Delete() defer netHandle.Close()
tapLink, fds, err := createLink(netHandle, endpoint.TapInterface.TAPIface.Name, &netlink.Tuntap{}, int(numCPUs)) tapLink, fds, err := createLink(netHandle, endpoint.TapInterface.TAPIface.Name, &netlink.Tuntap{}, int(numCPUs))
if err != nil { if err != nil {
@ -192,7 +192,7 @@ func unTapNetwork(name string) error {
if err != nil { if err != nil {
return err return err
} }
defer netHandle.Delete() defer netHandle.Close()
tapLink, err := getLinkByName(netHandle, name, &netlink.Tuntap{}) tapLink, err := getLinkByName(netHandle, name, &netlink.Tuntap{})
if err != nil { if err != nil {
return fmt.Errorf("Could not get TAP interface: %s", err) return fmt.Errorf("Could not get TAP interface: %s", err)

View File

@ -173,7 +173,7 @@ func tuntapNetwork(endpoint *TuntapEndpoint, numCPUs uint32, disableVhostNet boo
if err != nil { if err != nil {
return err return err
} }
defer netHandle.Delete() defer netHandle.Close()
tapLink, _, err := createLink(netHandle, endpoint.TuntapInterface.TAPIface.Name, &netlink.Tuntap{}, int(numCPUs)) tapLink, _, err := createLink(netHandle, endpoint.TuntapInterface.TAPIface.Name, &netlink.Tuntap{}, int(numCPUs))
if err != nil { if err != nil {
@ -201,7 +201,7 @@ func unTuntapNetwork(name string) error {
if err != nil { if err != nil {
return err return err
} }
defer netHandle.Delete() defer netHandle.Close()
tapLink, err := getLinkByName(netHandle, name, &netlink.Tuntap{}) tapLink, err := getLinkByName(netHandle, name, &netlink.Tuntap{})
if err != nil { if err != nil {
return fmt.Errorf("Could not get TAP interface: %s", err) return fmt.Errorf("Could not get TAP interface: %s", err)