1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Vendoring netlink library

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>
This commit is contained in:
Flavio Crisciani 2017-06-06 09:23:14 -07:00
parent d5c69190d1
commit acf9c53292
16 changed files with 856 additions and 56 deletions

View file

@ -19,11 +19,11 @@ github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
github.com/godbus/dbus 5f6efc7ef2759c81b7ba876593971bfce311eab3
github.com/gogo/protobuf 8d70fb3182befc465c4a1eac8ad4d38ff49778e2
github.com/golang/protobuf/proto f7137ae6b19afbfd61a94b746fda3b3fe0491874
github.com/golang/protobuf f7137ae6b19afbfd61a94b746fda3b3fe0491874
github.com/gorilla/context 215affda49addc4c8ef7e2534915df2c8c35c6cd
github.com/gorilla/mux 8096f47503459bcc74d1f4c487b7e6e42e5746b5
github.com/hashicorp/consul/api 954aec66231b79c161a4122b023fbcad13047f79
github.com/hashicorp/go-msgpack/codec 71c2886f5a673a35f909803f38ece5810165097b
github.com/hashicorp/consul 954aec66231b79c161a4122b023fbcad13047f79
github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
github.com/hashicorp/go-multierror 2167c8ec40776024589f483a6b836489e47e1049
github.com/hashicorp/memberlist v0.1.0
github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
@ -31,13 +31,13 @@ github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d
github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
github.com/mattn/go-shellwords 525bedee691b5a8df547cb5cf9f86b7fb1883e24
github.com/miekg/dns d27455715200c7d3e321a1e5cadb27c9ee0b0f02
github.com/opencontainers/runc/libcontainer ba1568de399395774ad84c2ace65937814c542ed
github.com/samuel/go-zookeeper/zk d0e0d8e11f318e000a8cc434616d69e329edc374
github.com/opencontainers/runc ba1568de399395774ad84c2ace65937814c542ed
github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
github.com/seccomp/libseccomp-golang 1b506fc7c24eec5a3693cdcbed40d9c226cfc6a1
github.com/stretchr/testify dab07ac62d4905d3e48d17dc549c684ac3b7c15a
github.com/syndtr/gocapability/capability 2c00daeb6c3b45114c80ac44119e7b8801fdd852
github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852
github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
github.com/vishvananda/netlink 1e86b2bee5b6a7d377e4c02bb7f98209d6a7297c
github.com/vishvananda/netlink bd6d5de5ccef2d66b0a26177928d0d8895d7f969
github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
golang.org/x/net c427ad74c6d7a814201695e9ffde0c5d400a7674
golang.org/x/sys 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9

View file

@ -10,11 +10,13 @@ import (
// include a mask, so it stores the address as a net.IPNet.
type Addr struct {
*net.IPNet
Label string
Flags int
Scope int
Peer *net.IPNet
Broadcast net.IP
Label string
Flags int
Scope int
Peer *net.IPNet
Broadcast net.IP
PreferedLft int
ValidLft int
}
// String returns $ip/$netmask $label

View file

@ -195,10 +195,16 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
}
addr.IPNet = local
case syscall.IFA_BROADCAST:
addr.Broadcast = attr.Value
case syscall.IFA_LABEL:
addr.Label = string(attr.Value[:len(attr.Value)-1])
case IFA_FLAGS:
addr.Flags = int(native.Uint32(attr.Value[0:4]))
case nl.IFA_CACHEINFO:
ci := nl.DeserializeIfaCacheInfo(attr.Value)
addr.PreferedLft = int(ci.IfaPrefered)
addr.ValidLft = int(ci.IfaValid)
}
}
@ -216,6 +222,10 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
type AddrUpdate struct {
LinkAddress net.IPNet
LinkIndex int
Flags int
Scope int
PreferedLft int
ValidLft int
NewAddr bool // true=added false=deleted
}
@ -263,7 +273,13 @@ func addrSubscribe(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-cha
continue
}
ch <- AddrUpdate{LinkAddress: *addr.IPNet, LinkIndex: ifindex, NewAddr: msgType == syscall.RTM_NEWADDR}
ch <- AddrUpdate{LinkAddress: *addr.IPNet,
LinkIndex: ifindex,
NewAddr: msgType == syscall.RTM_NEWADDR,
Flags: addr.Flags,
Scope: addr.Scope,
PreferedLft: addr.PreferedLft,
ValidLft: addr.ValidLft}
}
}
}()

View file

@ -141,19 +141,19 @@ func (h *Handle) FilterAdd(filter Filter) error {
}
if native != networkOrder {
// Copy Tcu32Sel.
cSel := sel
// Copy TcU32Sel.
cSel := *sel
keys := make([]nl.TcU32Key, cap(sel.Keys))
copy(keys, sel.Keys)
cSel.Keys = keys
sel = cSel
sel = &cSel
// Handle the endianness of attributes
sel.Offmask = native.Uint16(htons(sel.Offmask))
sel.Hmask = native.Uint32(htonl(sel.Hmask))
for _, key := range sel.Keys {
key.Mask = native.Uint32(htonl(key.Mask))
key.Val = native.Uint32(htonl(key.Val))
for i, key := range sel.Keys {
sel.Keys[i].Mask = native.Uint32(htonl(key.Mask))
sel.Keys[i].Val = native.Uint32(htonl(key.Val))
}
}
sel.Nkeys = uint8(len(sel.Keys))
@ -453,15 +453,11 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
// Handle the endianness of attributes
u32.Sel.Offmask = native.Uint16(htons(sel.Offmask))
u32.Sel.Hmask = native.Uint32(htonl(sel.Hmask))
for _, key := range u32.Sel.Keys {
key.Mask = native.Uint32(htonl(key.Mask))
key.Val = native.Uint32(htonl(key.Val))
for i, key := range u32.Sel.Keys {
u32.Sel.Keys[i].Mask = native.Uint32(htonl(key.Mask))
u32.Sel.Keys[i].Val = native.Uint32(htonl(key.Val))
}
}
// only parse if we have a very basic redirect
if sel.Flags&nl.TC_U32_TERMINAL == 0 || sel.Nkeys != 1 {
return detailed, nil
}
case nl.TCA_U32_ACT:
tables, err := nl.ParseRouteAttr(datum.Value)
if err != nil {

View file

@ -0,0 +1,167 @@
package netlink
import (
"fmt"
"syscall"
"github.com/vishvananda/netlink/nl"
)
type GenlOp struct {
ID uint32
Flags uint32
}
type GenlMulticastGroup struct {
ID uint32
Name string
}
type GenlFamily struct {
ID uint16
HdrSize uint32
Name string
Version uint32
MaxAttr uint32
Ops []GenlOp
Groups []GenlMulticastGroup
}
func parseOps(b []byte) ([]GenlOp, error) {
attrs, err := nl.ParseRouteAttr(b)
if err != nil {
return nil, err
}
ops := make([]GenlOp, 0, len(attrs))
for _, a := range attrs {
nattrs, err := nl.ParseRouteAttr(a.Value)
if err != nil {
return nil, err
}
var op GenlOp
for _, na := range nattrs {
switch na.Attr.Type {
case nl.GENL_CTRL_ATTR_OP_ID:
op.ID = native.Uint32(na.Value)
case nl.GENL_CTRL_ATTR_OP_FLAGS:
op.Flags = native.Uint32(na.Value)
}
}
ops = append(ops, op)
}
return ops, nil
}
func parseMulticastGroups(b []byte) ([]GenlMulticastGroup, error) {
attrs, err := nl.ParseRouteAttr(b)
if err != nil {
return nil, err
}
groups := make([]GenlMulticastGroup, 0, len(attrs))
for _, a := range attrs {
nattrs, err := nl.ParseRouteAttr(a.Value)
if err != nil {
return nil, err
}
var g GenlMulticastGroup
for _, na := range nattrs {
switch na.Attr.Type {
case nl.GENL_CTRL_ATTR_MCAST_GRP_NAME:
g.Name = nl.BytesToString(na.Value)
case nl.GENL_CTRL_ATTR_MCAST_GRP_ID:
g.ID = native.Uint32(na.Value)
}
}
groups = append(groups, g)
}
return groups, nil
}
func (f *GenlFamily) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
for _, a := range attrs {
switch a.Attr.Type {
case nl.GENL_CTRL_ATTR_FAMILY_NAME:
f.Name = nl.BytesToString(a.Value)
case nl.GENL_CTRL_ATTR_FAMILY_ID:
f.ID = native.Uint16(a.Value)
case nl.GENL_CTRL_ATTR_VERSION:
f.Version = native.Uint32(a.Value)
case nl.GENL_CTRL_ATTR_HDRSIZE:
f.HdrSize = native.Uint32(a.Value)
case nl.GENL_CTRL_ATTR_MAXATTR:
f.MaxAttr = native.Uint32(a.Value)
case nl.GENL_CTRL_ATTR_OPS:
ops, err := parseOps(a.Value)
if err != nil {
return err
}
f.Ops = ops
case nl.GENL_CTRL_ATTR_MCAST_GROUPS:
groups, err := parseMulticastGroups(a.Value)
if err != nil {
return err
}
f.Groups = groups
}
}
return nil
}
func parseFamilies(msgs [][]byte) ([]*GenlFamily, error) {
families := make([]*GenlFamily, 0, len(msgs))
for _, m := range msgs {
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
if err != nil {
return nil, err
}
family := &GenlFamily{}
if err := family.parseAttributes(attrs); err != nil {
return nil, err
}
families = append(families, family)
}
return families, nil
}
func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
msg := &nl.Genlmsg{
Command: nl.GENL_CTRL_CMD_GETFAMILY,
Version: nl.GENL_CTRL_VERSION,
}
req := h.newNetlinkRequest(nl.GENL_ID_CTRL, syscall.NLM_F_DUMP)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
return parseFamilies(msgs)
}
func GenlFamilyList() ([]*GenlFamily, error) {
return pkgHandle.GenlFamilyList()
}
func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) {
msg := &nl.Genlmsg{
Command: nl.GENL_CTRL_CMD_GETFAMILY,
Version: nl.GENL_CTRL_VERSION,
}
req := h.newNetlinkRequest(nl.GENL_ID_CTRL, 0)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_CTRL_ATTR_FAMILY_NAME, nl.ZeroTerminated(name)))
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
families, err := parseFamilies(msgs)
if len(families) != 1 {
return nil, fmt.Errorf("invalid response for GENL_CTRL_CMD_GETFAMILY")
}
return families[0], nil
}
func GenlFamilyGet(name string) (*GenlFamily, error) {
return pkgHandle.GenlFamilyGet(name)
}

View file

@ -0,0 +1,25 @@
// +build !linux
package netlink
type GenlOp struct{}
type GenlMulticastGroup struct{}
type GenlFamily struct{}
func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
return nil, ErrNotImplemented
}
func GenlFamilyList() ([]*GenlFamily, error) {
return nil, ErrNotImplemented
}
func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) {
return nil, ErrNotImplemented
}
func GenlFamilyGet(name string) (*GenlFamily, error) {
return nil, ErrNotImplemented
}

View file

@ -0,0 +1,238 @@
package netlink
import (
"fmt"
"net"
"strings"
"syscall"
"github.com/vishvananda/netlink/nl"
)
type PDP struct {
Version uint32
TID uint64
PeerAddress net.IP
MSAddress net.IP
Flow uint16
NetNSFD uint32
ITEI uint32
OTEI uint32
}
func (pdp *PDP) String() string {
elems := []string{}
elems = append(elems, fmt.Sprintf("Version: %d", pdp.Version))
if pdp.Version == 0 {
elems = append(elems, fmt.Sprintf("TID: %d", pdp.TID))
} else if pdp.Version == 1 {
elems = append(elems, fmt.Sprintf("TEI: %d/%d", pdp.ITEI, pdp.OTEI))
}
elems = append(elems, fmt.Sprintf("MS-Address: %s", pdp.MSAddress))
elems = append(elems, fmt.Sprintf("Peer-Address: %s", pdp.PeerAddress))
return fmt.Sprintf("{%s}", strings.Join(elems, " "))
}
func (p *PDP) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
for _, a := range attrs {
switch a.Attr.Type {
case nl.GENL_GTP_ATTR_VERSION:
p.Version = native.Uint32(a.Value)
case nl.GENL_GTP_ATTR_TID:
p.TID = native.Uint64(a.Value)
case nl.GENL_GTP_ATTR_PEER_ADDRESS:
p.PeerAddress = net.IP(a.Value)
case nl.GENL_GTP_ATTR_MS_ADDRESS:
p.MSAddress = net.IP(a.Value)
case nl.GENL_GTP_ATTR_FLOW:
p.Flow = native.Uint16(a.Value)
case nl.GENL_GTP_ATTR_NET_NS_FD:
p.NetNSFD = native.Uint32(a.Value)
case nl.GENL_GTP_ATTR_I_TEI:
p.ITEI = native.Uint32(a.Value)
case nl.GENL_GTP_ATTR_O_TEI:
p.OTEI = native.Uint32(a.Value)
}
}
return nil
}
func parsePDP(msgs [][]byte) ([]*PDP, error) {
pdps := make([]*PDP, 0, len(msgs))
for _, m := range msgs {
attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
if err != nil {
return nil, err
}
pdp := &PDP{}
if err := pdp.parseAttributes(attrs); err != nil {
return nil, err
}
pdps = append(pdps, pdp)
}
return pdps, nil
}
func (h *Handle) GTPPDPList() ([]*PDP, error) {
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
if err != nil {
return nil, err
}
msg := &nl.Genlmsg{
Command: nl.GENL_GTP_CMD_GETPDP,
Version: nl.GENL_GTP_VERSION,
}
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_DUMP)
req.AddData(msg)
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
return parsePDP(msgs)
}
func GTPPDPList() ([]*PDP, error) {
return pkgHandle.GTPPDPList()
}
func gtpPDPGet(req *nl.NetlinkRequest) (*PDP, error) {
msgs, err := req.Execute(syscall.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
pdps, err := parsePDP(msgs)
if err != nil {
return nil, err
}
if len(pdps) != 1 {
return nil, fmt.Errorf("invalid reqponse for GENL_GTP_CMD_GETPDP")
}
return pdps[0], nil
}
func (h *Handle) GTPPDPByTID(link Link, tid int) (*PDP, error) {
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
if err != nil {
return nil, err
}
msg := &nl.Genlmsg{
Command: nl.GENL_GTP_CMD_GETPDP,
Version: nl.GENL_GTP_VERSION,
}
req := h.newNetlinkRequest(int(f.ID), 0)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(uint64(tid))))
return gtpPDPGet(req)
}
func GTPPDPByTID(link Link, tid int) (*PDP, error) {
return pkgHandle.GTPPDPByTID(link, tid)
}
func (h *Handle) GTPPDPByITEI(link Link, itei int) (*PDP, error) {
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
if err != nil {
return nil, err
}
msg := &nl.Genlmsg{
Command: nl.GENL_GTP_CMD_GETPDP,
Version: nl.GENL_GTP_VERSION,
}
req := h.newNetlinkRequest(int(f.ID), 0)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(1)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(uint32(itei))))
return gtpPDPGet(req)
}
func GTPPDPByITEI(link Link, itei int) (*PDP, error) {
return pkgHandle.GTPPDPByITEI(link, itei)
}
func (h *Handle) GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) {
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
if err != nil {
return nil, err
}
msg := &nl.Genlmsg{
Command: nl.GENL_GTP_CMD_GETPDP,
Version: nl.GENL_GTP_VERSION,
}
req := h.newNetlinkRequest(int(f.ID), 0)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(0)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(addr.To4())))
return gtpPDPGet(req)
}
func GTPPDPByMSAddress(link Link, addr net.IP) (*PDP, error) {
return pkgHandle.GTPPDPByMSAddress(link, addr)
}
func (h *Handle) GTPPDPAdd(link Link, pdp *PDP) error {
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
if err != nil {
return err
}
msg := &nl.Genlmsg{
Command: nl.GENL_GTP_CMD_NEWPDP,
Version: nl.GENL_GTP_VERSION,
}
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_PEER_ADDRESS, []byte(pdp.PeerAddress.To4())))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_MS_ADDRESS, []byte(pdp.MSAddress.To4())))
switch pdp.Version {
case 0:
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_FLOW, nl.Uint16Attr(pdp.Flow)))
case 1:
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_O_TEI, nl.Uint32Attr(pdp.OTEI)))
default:
return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
}
_, err = req.Execute(syscall.NETLINK_GENERIC, 0)
return err
}
func GTPPDPAdd(link Link, pdp *PDP) error {
return pkgHandle.GTPPDPAdd(link, pdp)
}
func (h *Handle) GTPPDPDel(link Link, pdp *PDP) error {
f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
if err != nil {
return err
}
msg := &nl.Genlmsg{
Command: nl.GENL_GTP_CMD_DELPDP,
Version: nl.GENL_GTP_VERSION,
}
req := h.newNetlinkRequest(int(f.ID), syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req.AddData(msg)
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_VERSION, nl.Uint32Attr(pdp.Version)))
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_LINK, nl.Uint32Attr(uint32(link.Attrs().Index))))
switch pdp.Version {
case 0:
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_TID, nl.Uint64Attr(pdp.TID)))
case 1:
req.AddData(nl.NewRtAttr(nl.GENL_GTP_ATTR_I_TEI, nl.Uint32Attr(pdp.ITEI)))
default:
return fmt.Errorf("unsupported GTP version: %d", pdp.Version)
}
_, err = req.Execute(syscall.NETLINK_GENERIC, 0)
return err
}
func GTPPDPDel(link Link, pdp *PDP) error {
return pkgHandle.GTPPDPDel(link, pdp)
}

View file

@ -170,6 +170,7 @@ type LinkStatistics64 struct {
type LinkXdp struct {
Fd int
Attached bool
Flags uint32
}
// Device links cannot be created via netlink. These links
@ -215,6 +216,8 @@ func (ifb *Ifb) Type() string {
// Bridge links are simple linux bridges
type Bridge struct {
LinkAttrs
MulticastSnooping *bool
HelloTime *uint32
}
func (bridge *Bridge) Attrs() *LinkAttrs {
@ -590,7 +593,11 @@ type Bond struct {
LacpRate BondLacpRate
AdSelect BondAdSelect
// looking at iproute tool AdInfo can only be retrived. It can't be set.
AdInfo *BondAdInfo
AdInfo *BondAdInfo
AdActorSysPrio int
AdUserPortKey int
AdActorSystem net.HardwareAddr
TlbDynamicLb int
}
func NewLinkBond(atr LinkAttrs) *Bond {
@ -618,6 +625,10 @@ func NewLinkBond(atr LinkAttrs) *Bond {
PackersPerSlave: -1,
LacpRate: -1,
AdSelect: -1,
AdActorSysPrio: -1,
AdUserPortKey: -1,
AdActorSystem: nil,
TlbDynamicLb: -1,
}
}
@ -731,8 +742,32 @@ func (vrf *Vrf) Type() string {
return "vrf"
}
type GTP struct {
LinkAttrs
FD0 int
FD1 int
Role int
PDPHashsize int
}
func (gtp *GTP) Attrs() *LinkAttrs {
return &gtp.LinkAttrs
}
func (gtp *GTP) Type() string {
return "gtp"
}
// iproute2 supported devices;
// vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
// gre | gretap | ip6gre | ip6gretap | vti | nlmon |
// bond_slave | ipvlan
// LinkNotFoundError wraps the various not found errors when
// getting/reading links. This is intended for better error
// handling by dependent code so that "not found error" can
// be distinguished from other errors
type LinkNotFoundError struct {
error
}

View file

@ -103,7 +103,7 @@ func (h *Handle) SetPromiscOn(link Link) error {
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Change = syscall.IFF_PROMISC
msg.Flags = syscall.IFF_UP
msg.Flags = syscall.IFF_PROMISC
msg.Index = int32(base.Index)
req.AddData(msg)
@ -111,6 +111,16 @@ func (h *Handle) SetPromiscOn(link Link) error {
return err
}
func BridgeSetMcastSnoop(link Link, on bool) error {
return pkgHandle.BridgeSetMcastSnoop(link, on)
}
func (h *Handle) BridgeSetMcastSnoop(link Link, on bool) error {
bridge := link.(*Bridge)
bridge.MulticastSnooping = &on
return h.linkModify(bridge, syscall.NLM_F_ACK)
}
func SetPromiscOn(link Link) error {
return pkgHandle.SetPromiscOn(link)
}
@ -122,7 +132,7 @@ func (h *Handle) SetPromiscOff(link Link) error {
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Change = syscall.IFF_PROMISC
msg.Flags = 0 & ^syscall.IFF_UP
msg.Flags = 0 & ^syscall.IFF_PROMISC
msg.Index = int32(base.Index)
req.AddData(msg)
@ -659,6 +669,18 @@ func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) {
if bond.AdSelect >= 0 {
nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_SELECT, nl.Uint8Attr(uint8(bond.AdSelect)))
}
if bond.AdActorSysPrio >= 0 {
nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_ACTOR_SYS_PRIO, nl.Uint16Attr(uint16(bond.AdActorSysPrio)))
}
if bond.AdUserPortKey >= 0 {
nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_USER_PORT_KEY, nl.Uint16Attr(uint16(bond.AdUserPortKey)))
}
if bond.AdActorSystem != nil {
nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_ACTOR_SYSTEM, []byte(bond.AdActorSystem))
}
if bond.TlbDynamicLb >= 0 {
nl.NewRtAttrChild(data, nl.IFLA_BOND_TLB_DYNAMIC_LB, nl.Uint8Attr(uint8(bond.TlbDynamicLb)))
}
}
// LinkAdd adds a new link device. The type and features of the device
@ -672,7 +694,10 @@ func LinkAdd(link Link) error {
// are taken fromt the parameters in the link object.
// Equivalent to: `ip link add $link`
func (h *Handle) LinkAdd(link Link) error {
// TODO: set mtu and hardware address
return h.linkModify(link, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
}
func (h *Handle) linkModify(link Link, flags int) error {
// TODO: support extra data for macvlan
base := link.Attrs()
@ -719,7 +744,7 @@ func (h *Handle) LinkAdd(link Link) error {
return nil
}
req := h.newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
req := h.newNetlinkRequest(syscall.RTM_NEWLINK, flags)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
// TODO: make it shorter
@ -767,6 +792,11 @@ func (h *Handle) LinkAdd(link Link) error {
req.AddData(qlen)
}
if base.HardwareAddr != nil {
hwaddr := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(base.HardwareAddr))
req.AddData(hwaddr)
}
if base.Namespace != nil {
var attr *nl.RtAttr
switch base.Namespace.(type) {
@ -830,6 +860,10 @@ func (h *Handle) LinkAdd(link Link) error {
addVtiAttrs(vti, linkInfo)
} else if vrf, ok := link.(*Vrf); ok {
addVrfAttrs(vrf, linkInfo)
} else if bridge, ok := link.(*Bridge); ok {
addBridgeAttrs(bridge, linkInfo)
} else if gtp, ok := link.(*GTP); ok {
addGTPAttrs(gtp, linkInfo)
}
req.AddData(linkInfo)
@ -885,7 +919,7 @@ func (h *Handle) linkByNameDump(name string) (Link, error) {
return link, nil
}
}
return nil, fmt.Errorf("Link %s not found", name)
return nil, LinkNotFoundError{fmt.Errorf("Link %s not found", name)}
}
func (h *Handle) linkByAliasDump(alias string) (Link, error) {
@ -899,7 +933,7 @@ func (h *Handle) linkByAliasDump(alias string) (Link, error) {
return link, nil
}
}
return nil, fmt.Errorf("Link alias %s not found", alias)
return nil, LinkNotFoundError{fmt.Errorf("Link alias %s not found", alias)}
}
// LinkByName finds a link by name and returns a pointer to the object.
@ -985,7 +1019,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
if err != nil {
if errno, ok := err.(syscall.Errno); ok {
if errno == syscall.ENODEV {
return nil, fmt.Errorf("Link not found")
return nil, LinkNotFoundError{fmt.Errorf("Link not found")}
}
}
return nil, err
@ -993,7 +1027,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
switch {
case len(msgs) == 0:
return nil, fmt.Errorf("Link not found")
return nil, LinkNotFoundError{fmt.Errorf("Link not found")}
case len(msgs) == 1:
return LinkDeserialize(nil, msgs[0])
@ -1063,6 +1097,8 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
link = &Vti{}
case "vrf":
link = &Vrf{}
case "gtp":
link = &GTP{}
default:
link = &GenericLink{LinkType: linkType}
}
@ -1092,6 +1128,10 @@ func LinkDeserialize(hdr *syscall.NlMsghdr, m []byte) (Link, error) {
parseVtiData(link, data)
case "vrf":
parseVrfData(link, data)
case "bridge":
parseBridgeData(link, data)
case "gtp":
parseGTPData(link, data)
}
}
}
@ -1288,6 +1328,22 @@ func (h *Handle) LinkSetFlood(link Link, mode bool) error {
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD)
}
func LinkSetBrProxyArp(link Link, mode bool) error {
return pkgHandle.LinkSetBrProxyArp(link, mode)
}
func (h *Handle) LinkSetBrProxyArp(link Link, mode bool) error {
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP)
}
func LinkSetBrProxyArpWiFi(link Link, mode bool) error {
return pkgHandle.LinkSetBrProxyArpWiFi(link, mode)
}
func (h *Handle) LinkSetBrProxyArpWiFi(link Link, mode bool) error {
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROXYARP_WIFI)
}
func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
base := link.Attrs()
h.ensureIndex(base)
@ -1370,7 +1426,7 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
}
func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
bond := NewLinkBond(NewLinkAttrs())
bond := link.(*Bond)
for i := range data {
switch data[i].Attr.Type {
case nl.IFLA_BOND_MODE:
@ -1419,6 +1475,14 @@ func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
bond.AdSelect = BondAdSelect(data[i].Value[0])
case nl.IFLA_BOND_AD_INFO:
// TODO: implement
case nl.IFLA_BOND_AD_ACTOR_SYS_PRIO:
bond.AdActorSysPrio = int(native.Uint16(data[i].Value[0:2]))
case nl.IFLA_BOND_AD_USER_PORT_KEY:
bond.AdUserPortKey = int(native.Uint16(data[i].Value[0:2]))
case nl.IFLA_BOND_AD_ACTOR_SYSTEM:
bond.AdActorSystem = net.HardwareAddr(data[i].Value[0:6])
case nl.IFLA_BOND_TLB_DYNAMIC_LB:
bond.TlbDynamicLb = int(data[i].Value[0])
}
}
}
@ -1566,6 +1630,8 @@ func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) {
b := make([]byte, 4)
native.PutUint32(b, uint32(xdp.Fd))
nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FD, b)
native.PutUint32(b, xdp.Flags)
nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FLAGS, b)
req.AddData(attrs)
}
@ -1581,6 +1647,8 @@ func parseLinkXdp(data []byte) (*LinkXdp, error) {
xdp.Fd = int(native.Uint32(attr.Value[0:4]))
case nl.IFLA_XDP_ATTACHED:
xdp.Attached = attr.Value[0] != 0
case nl.IFLA_XDP_FLAGS:
xdp.Flags = native.Uint32(attr.Value[0:4])
}
}
return xdp, nil
@ -1678,3 +1746,53 @@ func parseVrfData(link Link, data []syscall.NetlinkRouteAttr) {
}
}
}
func addBridgeAttrs(bridge *Bridge, linkInfo *nl.RtAttr) {
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
if bridge.MulticastSnooping != nil {
nl.NewRtAttrChild(data, nl.IFLA_BR_MCAST_SNOOPING, boolToByte(*bridge.MulticastSnooping))
}
if bridge.HelloTime != nil {
nl.NewRtAttrChild(data, nl.IFLA_BR_HELLO_TIME, nl.Uint32Attr(*bridge.HelloTime))
}
}
func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) {
br := bridge.(*Bridge)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_BR_HELLO_TIME:
helloTime := native.Uint32(datum.Value[0:4])
br.HelloTime = &helloTime
case nl.IFLA_BR_MCAST_SNOOPING:
mcastSnooping := datum.Value[0] == 1
br.MulticastSnooping = &mcastSnooping
}
}
}
func addGTPAttrs(gtp *GTP, linkInfo *nl.RtAttr) {
data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
nl.NewRtAttrChild(data, nl.IFLA_GTP_FD0, nl.Uint32Attr(uint32(gtp.FD0)))
nl.NewRtAttrChild(data, nl.IFLA_GTP_FD1, nl.Uint32Attr(uint32(gtp.FD1)))
nl.NewRtAttrChild(data, nl.IFLA_GTP_PDP_HASHSIZE, nl.Uint32Attr(131072))
if gtp.Role != nl.GTP_ROLE_GGSN {
nl.NewRtAttrChild(data, nl.IFLA_GTP_ROLE, nl.Uint32Attr(uint32(gtp.Role)))
}
}
func parseGTPData(link Link, data []syscall.NetlinkRouteAttr) {
gtp := link.(*GTP)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_GTP_FD0:
gtp.FD0 = int(native.Uint32(datum.Value))
case nl.IFLA_GTP_FD1:
gtp.FD1 = int(native.Uint32(datum.Value))
case nl.IFLA_GTP_PDP_HASHSIZE:
gtp.PDPHashsize = int(native.Uint32(datum.Value))
case nl.IFLA_GTP_ROLE:
gtp.Role = int(native.Uint32(datum.Value))
}
}
}

View file

@ -45,3 +45,32 @@ func (msg *IfAddrmsg) Serialize() []byte {
func (msg *IfAddrmsg) Len() int {
return syscall.SizeofIfAddrmsg
}
// struct ifa_cacheinfo {
// __u32 ifa_prefered;
// __u32 ifa_valid;
// __u32 cstamp; /* created timestamp, hundredths of seconds */
// __u32 tstamp; /* updated timestamp, hundredths of seconds */
// };
const IFA_CACHEINFO = 6
const SizeofIfaCacheInfo = 0x10
type IfaCacheInfo struct {
IfaPrefered uint32
IfaValid uint32
Cstamp uint32
Tstamp uint32
}
func (msg *IfaCacheInfo) Len() int {
return SizeofIfaCacheInfo
}
func DeserializeIfaCacheInfo(b []byte) *IfaCacheInfo {
return (*IfaCacheInfo)(unsafe.Pointer(&b[0:SizeofIfaCacheInfo][0]))
}
func (msg *IfaCacheInfo) Serialize() []byte {
return (*(*[SizeofIfaCacheInfo]byte)(unsafe.Pointer(msg)))[:]
}

View file

@ -0,0 +1,89 @@
package nl
import (
"unsafe"
)
const SizeofGenlmsg = 4
const (
GENL_ID_CTRL = 0x10
GENL_CTRL_VERSION = 2
GENL_CTRL_NAME = "nlctrl"
)
const (
GENL_CTRL_CMD_GETFAMILY = 3
)
const (
GENL_CTRL_ATTR_UNSPEC = iota
GENL_CTRL_ATTR_FAMILY_ID
GENL_CTRL_ATTR_FAMILY_NAME
GENL_CTRL_ATTR_VERSION
GENL_CTRL_ATTR_HDRSIZE
GENL_CTRL_ATTR_MAXATTR
GENL_CTRL_ATTR_OPS
GENL_CTRL_ATTR_MCAST_GROUPS
)
const (
GENL_CTRL_ATTR_OP_UNSPEC = iota
GENL_CTRL_ATTR_OP_ID
GENL_CTRL_ATTR_OP_FLAGS
)
const (
GENL_ADMIN_PERM = 1 << iota
GENL_CMD_CAP_DO
GENL_CMD_CAP_DUMP
GENL_CMD_CAP_HASPOL
)
const (
GENL_CTRL_ATTR_MCAST_GRP_UNSPEC = iota
GENL_CTRL_ATTR_MCAST_GRP_NAME
GENL_CTRL_ATTR_MCAST_GRP_ID
)
const (
GENL_GTP_VERSION = 0
GENL_GTP_NAME = "gtp"
)
const (
GENL_GTP_CMD_NEWPDP = iota
GENL_GTP_CMD_DELPDP
GENL_GTP_CMD_GETPDP
)
const (
GENL_GTP_ATTR_UNSPEC = iota
GENL_GTP_ATTR_LINK
GENL_GTP_ATTR_VERSION
GENL_GTP_ATTR_TID
GENL_GTP_ATTR_PEER_ADDRESS
GENL_GTP_ATTR_MS_ADDRESS
GENL_GTP_ATTR_FLOW
GENL_GTP_ATTR_NET_NS_FD
GENL_GTP_ATTR_I_TEI
GENL_GTP_ATTR_O_TEI
GENL_GTP_ATTR_PAD
)
type Genlmsg struct {
Command uint8
Version uint8
}
func (msg *Genlmsg) Len() int {
return SizeofGenlmsg
}
func DeserializeGenlmsg(b []byte) *Genlmsg {
return (*Genlmsg)(unsafe.Pointer(&b[0:SizeofGenlmsg][0]))
}
func (msg *Genlmsg) Serialize() []byte {
return (*(*[SizeofGenlmsg]byte)(unsafe.Pointer(msg)))[:]
}

View file

@ -102,7 +102,10 @@ const (
IFLA_BRPORT_FAST_LEAVE
IFLA_BRPORT_LEARNING
IFLA_BRPORT_UNICAST_FLOOD
IFLA_BRPORT_MAX = IFLA_BRPORT_UNICAST_FLOOD
IFLA_BRPORT_PROXYARP
IFLA_BRPORT_LEARNING_SYNC
IFLA_BRPORT_PROXYARP_WIFI
IFLA_BRPORT_MAX = IFLA_BRPORT_PROXYARP_WIFI
)
const (
@ -151,6 +154,10 @@ const (
IFLA_BOND_AD_LACP_RATE
IFLA_BOND_AD_SELECT
IFLA_BOND_AD_INFO
IFLA_BOND_AD_ACTOR_SYS_PRIO
IFLA_BOND_AD_USER_PORT_KEY
IFLA_BOND_AD_ACTOR_SYSTEM
IFLA_BOND_TLB_DYNAMIC_LB
)
const (
@ -416,7 +423,8 @@ const (
IFLA_XDP_UNSPEC = iota
IFLA_XDP_FD /* fd of xdp program to attach, or -1 to remove */
IFLA_XDP_ATTACHED /* read-only bool indicating if prog is attached */
IFLA_XDP_MAX = IFLA_XDP_ATTACHED
IFLA_XDP_FLAGS /* xdp prog related flags */
IFLA_XDP_MAX = IFLA_XDP_FLAGS
)
const (
@ -452,3 +460,65 @@ const (
IFLA_VRF_UNSPEC = iota
IFLA_VRF_TABLE
)
const (
IFLA_BR_UNSPEC = iota
IFLA_BR_FORWARD_DELAY
IFLA_BR_HELLO_TIME
IFLA_BR_MAX_AGE
IFLA_BR_AGEING_TIME
IFLA_BR_STP_STATE
IFLA_BR_PRIORITY
IFLA_BR_VLAN_FILTERING
IFLA_BR_VLAN_PROTOCOL
IFLA_BR_GROUP_FWD_MASK
IFLA_BR_ROOT_ID
IFLA_BR_BRIDGE_ID
IFLA_BR_ROOT_PORT
IFLA_BR_ROOT_PATH_COST
IFLA_BR_TOPOLOGY_CHANGE
IFLA_BR_TOPOLOGY_CHANGE_DETECTED
IFLA_BR_HELLO_TIMER
IFLA_BR_TCN_TIMER
IFLA_BR_TOPOLOGY_CHANGE_TIMER
IFLA_BR_GC_TIMER
IFLA_BR_GROUP_ADDR
IFLA_BR_FDB_FLUSH
IFLA_BR_MCAST_ROUTER
IFLA_BR_MCAST_SNOOPING
IFLA_BR_MCAST_QUERY_USE_IFADDR
IFLA_BR_MCAST_QUERIER
IFLA_BR_MCAST_HASH_ELASTICITY
IFLA_BR_MCAST_HASH_MAX
IFLA_BR_MCAST_LAST_MEMBER_CNT
IFLA_BR_MCAST_STARTUP_QUERY_CNT
IFLA_BR_MCAST_LAST_MEMBER_INTVL
IFLA_BR_MCAST_MEMBERSHIP_INTVL
IFLA_BR_MCAST_QUERIER_INTVL
IFLA_BR_MCAST_QUERY_INTVL
IFLA_BR_MCAST_QUERY_RESPONSE_INTVL
IFLA_BR_MCAST_STARTUP_QUERY_INTVL
IFLA_BR_NF_CALL_IPTABLES
IFLA_BR_NF_CALL_IP6TABLES
IFLA_BR_NF_CALL_ARPTABLES
IFLA_BR_VLAN_DEFAULT_PVID
IFLA_BR_PAD
IFLA_BR_VLAN_STATS_ENABLED
IFLA_BR_MCAST_STATS_ENABLED
IFLA_BR_MCAST_IGMP_VERSION
IFLA_BR_MCAST_MLD_VERSION
IFLA_BR_MAX = IFLA_BR_MCAST_MLD_VERSION
)
const (
IFLA_GTP_UNSPEC = iota
IFLA_GTP_FD0
IFLA_GTP_FD1
IFLA_GTP_PDP_HASHSIZE
IFLA_GTP_ROLE
)
const (
GTP_ROLE_GGSN = iota
GTP_ROLE_SGSN
)

View file

@ -459,7 +459,7 @@ func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
}
type NetlinkSocket struct {
fd int
fd int32
lsa syscall.SockaddrNetlink
sync.Mutex
}
@ -470,7 +470,7 @@ func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
return nil, err
}
s := &NetlinkSocket{
fd: fd,
fd: int32(fd),
}
s.lsa.Family = syscall.AF_NETLINK
if err := syscall.Bind(fd, &s.lsa); err != nil {
@ -556,7 +556,7 @@ func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
return nil, err
}
s := &NetlinkSocket{
fd: fd,
fd: int32(fd),
}
s.lsa.Family = syscall.AF_NETLINK
@ -585,30 +585,32 @@ func SubscribeAt(newNs, curNs netns.NsHandle, protocol int, groups ...uint) (*Ne
}
func (s *NetlinkSocket) Close() {
syscall.Close(s.fd)
s.fd = -1
fd := int(atomic.SwapInt32(&s.fd, -1))
syscall.Close(fd)
}
func (s *NetlinkSocket) GetFd() int {
return s.fd
return int(atomic.LoadInt32(&s.fd))
}
func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
if s.fd < 0 {
fd := int(atomic.LoadInt32(&s.fd))
if fd < 0 {
return fmt.Errorf("Send called on a closed socket")
}
if err := syscall.Sendto(s.fd, request.Serialize(), 0, &s.lsa); err != nil {
if err := syscall.Sendto(fd, request.Serialize(), 0, &s.lsa); err != nil {
return err
}
return nil
}
func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
if s.fd < 0 {
fd := int(atomic.LoadInt32(&s.fd))
if fd < 0 {
return nil, fmt.Errorf("Receive called on a closed socket")
}
rb := make([]byte, syscall.Getpagesize())
nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
nr, _, err := syscall.Recvfrom(fd, rb, 0)
if err != nil {
return nil, err
}
@ -620,7 +622,8 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
}
func (s *NetlinkSocket) GetPid() (uint32, error) {
lsa, err := syscall.Getsockname(s.fd)
fd := int(atomic.LoadInt32(&s.fd))
lsa, err := syscall.Getsockname(fd)
if err != nil {
return 0, err
}

View file

@ -6,12 +6,14 @@ import (
// Protinfo represents bridge flags from netlink.
type Protinfo struct {
Hairpin bool
Guard bool
FastLeave bool
RootBlock bool
Learning bool
Flood bool
Hairpin bool
Guard bool
FastLeave bool
RootBlock bool
Learning bool
Flood bool
ProxyArp bool
ProxyArpWiFi bool
}
// String returns a list of enabled flags
@ -35,6 +37,12 @@ func (prot *Protinfo) String() string {
if prot.Flood {
boolStrings = append(boolStrings, "Flood")
}
if prot.ProxyArp {
boolStrings = append(boolStrings, "ProxyArp")
}
if prot.ProxyArpWiFi {
boolStrings = append(boolStrings, "ProxyArpWiFi")
}
return strings.Join(boolStrings, " ")
}

View file

@ -64,6 +64,10 @@ func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
pi.Learning = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_UNICAST_FLOOD:
pi.Flood = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_PROXYARP:
pi.ProxyArp = byteToBool(info.Value[0])
case nl.IFLA_BRPORT_PROXYARP_WIFI:
pi.ProxyArpWiFi = byteToBool(info.Value[0])
}
}
return &pi

View file

@ -401,7 +401,7 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
}
if filter != nil {
switch {
case filterMask&RT_FILTER_TABLE != 0 && route.Table != filter.Table:
case filterMask&RT_FILTER_TABLE != 0 && filter.Table != syscall.RT_TABLE_UNSPEC && route.Table != filter.Table:
continue
case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol:
continue