mirror of
https://github.com/vishvananda/netlink
synced 2024-12-28 01:22:18 +00:00
support netkit
netkit device is merged to Linux upstream: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=22360fad5889cbefe1eca695b0cc0273ab280b56 this PR add support to manage a netkit device in Golang authored-by: tangchen <tangchen.1@bytedance.com>
This commit is contained in:
parent
95ab6696a5
commit
f1333cd79a
40
link.go
40
link.go
@ -357,6 +357,46 @@ func (tuntap *Tuntap) Type() string {
|
||||
return "tuntap"
|
||||
}
|
||||
|
||||
type NetkitMode uint32
|
||||
|
||||
const (
|
||||
NETKIT_MODE_L2 NetkitMode = iota
|
||||
NETKIT_MODE_L3
|
||||
)
|
||||
|
||||
type NetkitPolicy int
|
||||
|
||||
const (
|
||||
NETKIT_POLICY_FORWARD NetkitPolicy = 0
|
||||
NETKIT_POLICY_BLACKHOLE NetkitPolicy = 2
|
||||
)
|
||||
|
||||
func (n *Netkit) IsPrimary() bool {
|
||||
return n.isPrimary
|
||||
}
|
||||
|
||||
// SetPeerAttrs will not take effect if trying to modify an existing netkit device
|
||||
func (n *Netkit) SetPeerAttrs(Attrs *LinkAttrs) {
|
||||
n.peerLinkAttrs = *Attrs
|
||||
}
|
||||
|
||||
type Netkit struct {
|
||||
LinkAttrs
|
||||
Mode NetkitMode
|
||||
Policy NetkitPolicy
|
||||
PeerPolicy NetkitPolicy
|
||||
isPrimary bool
|
||||
peerLinkAttrs LinkAttrs
|
||||
}
|
||||
|
||||
func (n *Netkit) Attrs() *LinkAttrs {
|
||||
return &n.LinkAttrs
|
||||
}
|
||||
|
||||
func (n *Netkit) Type() string {
|
||||
return "netkit"
|
||||
}
|
||||
|
||||
// Veth devices must specify PeerName on create
|
||||
type Veth struct {
|
||||
LinkAttrs
|
||||
|
@ -1634,6 +1634,10 @@ func (h *Handle) linkModify(link Link, flags int) error {
|
||||
if link.VlanProtocol != VLAN_PROTOCOL_UNKNOWN {
|
||||
data.AddRtAttr(nl.IFLA_VLAN_PROTOCOL, htons(uint16(link.VlanProtocol)))
|
||||
}
|
||||
case *Netkit:
|
||||
if err := addNetkitAttrs(link, linkInfo, flags); err != nil {
|
||||
return err
|
||||
}
|
||||
case *Veth:
|
||||
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
|
||||
peer := data.AddRtAttr(nl.VETH_INFO_PEER, nil)
|
||||
@ -1947,6 +1951,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
|
||||
link = &Bridge{}
|
||||
case "vlan":
|
||||
link = &Vlan{}
|
||||
case "netkit":
|
||||
link = &Netkit{}
|
||||
case "veth":
|
||||
link = &Veth{}
|
||||
case "wireguard":
|
||||
@ -2004,6 +2010,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
|
||||
return nil, err
|
||||
}
|
||||
switch linkType {
|
||||
case "netkit":
|
||||
parseNetkitData(link, data)
|
||||
case "vlan":
|
||||
parseVlanData(link, data)
|
||||
case "vxlan":
|
||||
@ -2544,6 +2552,80 @@ func (h *Handle) LinkSetGroup(link Link, group int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func addNetkitAttrs(nk *Netkit, linkInfo *nl.RtAttr, flag int) error {
|
||||
if nk.peerLinkAttrs.HardwareAddr != nil || nk.HardwareAddr != nil {
|
||||
return fmt.Errorf("netkit doesn't support setting Ethernet")
|
||||
}
|
||||
|
||||
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
|
||||
// Kernel will return error if trying to change the mode of an existing netkit device
|
||||
data.AddRtAttr(nl.IFLA_NETKIT_MODE, nl.Uint32Attr(uint32(nk.Mode)))
|
||||
data.AddRtAttr(nl.IFLA_NETKIT_POLICY, nl.Uint32Attr(uint32(nk.Policy)))
|
||||
data.AddRtAttr(nl.IFLA_NETKIT_PEER_POLICY, nl.Uint32Attr(uint32(nk.PeerPolicy)))
|
||||
|
||||
if (flag & unix.NLM_F_EXCL) == 0 {
|
||||
// Modifying peer link attributes will not take effect
|
||||
return nil
|
||||
}
|
||||
|
||||
peer := data.AddRtAttr(nl.IFLA_NETKIT_PEER_INFO, nil)
|
||||
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
|
||||
if nk.peerLinkAttrs.Flags&net.FlagUp != 0 {
|
||||
msg.Change = unix.IFF_UP
|
||||
msg.Flags = unix.IFF_UP
|
||||
}
|
||||
if nk.peerLinkAttrs.Index != 0 {
|
||||
msg.Index = int32(nk.peerLinkAttrs.Index)
|
||||
}
|
||||
peer.AddChild(msg)
|
||||
if nk.peerLinkAttrs.Name != "" {
|
||||
peer.AddRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(nk.peerLinkAttrs.Name))
|
||||
}
|
||||
if nk.peerLinkAttrs.MTU > 0 {
|
||||
peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(nk.peerLinkAttrs.MTU)))
|
||||
}
|
||||
if nk.peerLinkAttrs.GSOMaxSegs > 0 {
|
||||
peer.AddRtAttr(unix.IFLA_GSO_MAX_SEGS, nl.Uint32Attr(nk.peerLinkAttrs.GSOMaxSegs))
|
||||
}
|
||||
if nk.peerLinkAttrs.GSOMaxSize > 0 {
|
||||
peer.AddRtAttr(unix.IFLA_GSO_MAX_SIZE, nl.Uint32Attr(nk.peerLinkAttrs.GSOMaxSize))
|
||||
}
|
||||
if nk.peerLinkAttrs.GSOIPv4MaxSize > 0 {
|
||||
peer.AddRtAttr(unix.IFLA_GSO_IPV4_MAX_SIZE, nl.Uint32Attr(nk.peerLinkAttrs.GSOIPv4MaxSize))
|
||||
}
|
||||
if nk.peerLinkAttrs.GROIPv4MaxSize > 0 {
|
||||
peer.AddRtAttr(unix.IFLA_GRO_IPV4_MAX_SIZE, nl.Uint32Attr(nk.peerLinkAttrs.GROIPv4MaxSize))
|
||||
}
|
||||
if nk.peerLinkAttrs.Namespace != nil {
|
||||
switch ns := nk.peerLinkAttrs.Namespace.(type) {
|
||||
case NsPid:
|
||||
peer.AddRtAttr(unix.IFLA_NET_NS_PID, nl.Uint32Attr(uint32(ns)))
|
||||
case NsFd:
|
||||
peer.AddRtAttr(unix.IFLA_NET_NS_FD, nl.Uint32Attr(uint32(ns)))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseNetkitData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
netkit := link.(*Netkit)
|
||||
for _, datum := range data {
|
||||
switch datum.Attr.Type {
|
||||
case nl.IFLA_NETKIT_PRIMARY:
|
||||
isPrimary := datum.Value[0:1][0]
|
||||
if isPrimary != 0 {
|
||||
netkit.isPrimary = true
|
||||
}
|
||||
case nl.IFLA_NETKIT_MODE:
|
||||
netkit.Mode = NetkitMode(native.Uint32(datum.Value[0:4]))
|
||||
case nl.IFLA_NETKIT_POLICY:
|
||||
netkit.Policy = NetkitPolicy(native.Uint32(datum.Value[0:4]))
|
||||
case nl.IFLA_NETKIT_PEER_POLICY:
|
||||
netkit.PeerPolicy = NetkitPolicy(native.Uint32(datum.Value[0:4]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
vlan := link.(*Vlan)
|
||||
for _, datum := range data {
|
||||
|
153
link_test.go
153
link_test.go
@ -67,6 +67,44 @@ func testLinkAddDel(t *testing.T, link Link) {
|
||||
}
|
||||
}
|
||||
|
||||
if resultPrimary, ok := result.(*Netkit); ok {
|
||||
if inputPrimary, ok := link.(*Netkit); ok {
|
||||
if resultPrimary.Policy != inputPrimary.Policy {
|
||||
t.Fatalf("Policy is %d, should be %d", int(resultPrimary.Policy), int(inputPrimary.Policy))
|
||||
}
|
||||
if resultPrimary.PeerPolicy != inputPrimary.PeerPolicy {
|
||||
t.Fatalf("Peer Policy is %d, should be %d", int(resultPrimary.PeerPolicy), int(inputPrimary.PeerPolicy))
|
||||
}
|
||||
if resultPrimary.Mode != inputPrimary.Mode {
|
||||
t.Fatalf("Mode is %d, should be %d", int(resultPrimary.Mode), int(inputPrimary.Mode))
|
||||
}
|
||||
|
||||
if inputPrimary.peerLinkAttrs.Name != "" {
|
||||
var resultPeer *Netkit
|
||||
pLink, err := LinkByName(inputPrimary.peerLinkAttrs.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get Peer netkit %s", inputPrimary.peerLinkAttrs.Name)
|
||||
}
|
||||
if resultPeer, ok = pLink.(*Netkit); !ok {
|
||||
t.Fatalf("Peer %s is incorrect type", inputPrimary.peerLinkAttrs.Name)
|
||||
}
|
||||
if resultPrimary.PeerPolicy != resultPeer.Policy {
|
||||
t.Fatalf("Peer Policy from primary is %d, should be %d", int(resultPrimary.PeerPolicy), int(resultPeer.Policy))
|
||||
}
|
||||
if resultPeer.PeerPolicy != resultPrimary.Policy {
|
||||
t.Fatalf("PeerPolicy from peer is %d, should be %d", int(resultPeer.PeerPolicy), int(resultPrimary.Policy))
|
||||
}
|
||||
if resultPrimary.Mode != resultPeer.Mode {
|
||||
t.Fatalf("Peer Mode from primary is %d, should be %d", int(resultPrimary.Mode), int(resultPeer.Mode))
|
||||
}
|
||||
if resultPrimary.IsPrimary() == resultPeer.IsPrimary() {
|
||||
t.Fatalf("Both primary and peer device has the same value in IsPrimary() %t", resultPrimary.IsPrimary())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if veth, ok := result.(*Veth); ok {
|
||||
if rBase.TxQLen != base.TxQLen {
|
||||
t.Fatalf("qlen is %d, should be %d", rBase.TxQLen, base.TxQLen)
|
||||
@ -108,15 +146,19 @@ func testLinkAddDel(t *testing.T, link Link) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// recent kernels set the parent index for veths in the response
|
||||
if rBase.ParentIndex == 0 && base.ParentIndex != 0 {
|
||||
t.Fatalf("Created link doesn't have parent %d but it should", base.ParentIndex)
|
||||
} else if rBase.ParentIndex != 0 && base.ParentIndex == 0 {
|
||||
t.Fatalf("Created link has parent %d but it shouldn't", rBase.ParentIndex)
|
||||
} else if rBase.ParentIndex != 0 && base.ParentIndex != 0 {
|
||||
if rBase.ParentIndex != base.ParentIndex {
|
||||
t.Fatalf("Link.ParentIndex doesn't match %d != %d", rBase.ParentIndex, base.ParentIndex)
|
||||
}
|
||||
|
||||
if _, ok := result.(*Veth); !ok {
|
||||
if _, ok := result.(*Netkit); !ok {
|
||||
// recent kernels set the parent index for veths/netkit in the response
|
||||
if rBase.ParentIndex == 0 && base.ParentIndex != 0 {
|
||||
t.Fatalf("Created link doesn't have parent %d but it should", base.ParentIndex)
|
||||
} else if rBase.ParentIndex != 0 && base.ParentIndex == 0 {
|
||||
t.Fatalf("Created link has parent %d but it shouldn't", rBase.ParentIndex)
|
||||
} else if rBase.ParentIndex != 0 && base.ParentIndex != 0 {
|
||||
if rBase.ParentIndex != base.ParentIndex {
|
||||
t.Fatalf("Link.ParentIndex doesn't match %d != %d", rBase.ParentIndex, base.ParentIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -868,6 +910,99 @@ func TestLinkAddDelMacvtap(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetkitPeerNs(t *testing.T) {
|
||||
minKernelRequired(t, 6, 7)
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
basens, err := netns.Get()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to get basens")
|
||||
}
|
||||
defer basens.Close()
|
||||
|
||||
nsOne, err := netns.New()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create nsOne")
|
||||
}
|
||||
defer nsOne.Close()
|
||||
|
||||
nsTwo, err := netns.New()
|
||||
if err != nil {
|
||||
t.Fatal("Failed to create nsTwo")
|
||||
}
|
||||
defer nsTwo.Close()
|
||||
|
||||
netkit := &Netkit{
|
||||
LinkAttrs: LinkAttrs{
|
||||
Name: "foo",
|
||||
Namespace: NsFd(basens),
|
||||
},
|
||||
Mode: NETKIT_MODE_L2,
|
||||
Policy: NETKIT_POLICY_FORWARD,
|
||||
PeerPolicy: NETKIT_POLICY_BLACKHOLE,
|
||||
}
|
||||
peerAttr := &LinkAttrs{
|
||||
Name: "bar",
|
||||
Namespace: NsFd(nsOne),
|
||||
}
|
||||
netkit.SetPeerAttrs(peerAttr)
|
||||
|
||||
if err := LinkAdd(netkit); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = LinkByName("bar")
|
||||
if err == nil {
|
||||
t.Fatal("netkit link bar is in nsTwo")
|
||||
}
|
||||
|
||||
_, err = LinkByName("foo")
|
||||
if err == nil {
|
||||
t.Fatal("netkit link foo is in nsTwo")
|
||||
}
|
||||
|
||||
err = netns.Set(basens)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to set basens")
|
||||
}
|
||||
|
||||
_, err = LinkByName("foo")
|
||||
if err != nil {
|
||||
t.Fatal("netkit link foo is not in basens")
|
||||
}
|
||||
|
||||
err = netns.Set(nsOne)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to set nsOne")
|
||||
}
|
||||
|
||||
_, err = LinkByName("bar")
|
||||
if err != nil {
|
||||
t.Fatal("netkit link bar is not in nsOne")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddDelNetkit(t *testing.T) {
|
||||
minKernelRequired(t, 6, 7)
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
netkit := &Netkit{
|
||||
LinkAttrs: LinkAttrs{
|
||||
Name: "foo",
|
||||
},
|
||||
Mode: NETKIT_MODE_L2,
|
||||
Policy: NETKIT_POLICY_FORWARD,
|
||||
PeerPolicy: NETKIT_POLICY_BLACKHOLE,
|
||||
}
|
||||
peerAttr := &LinkAttrs{
|
||||
Name: "bar",
|
||||
}
|
||||
netkit.SetPeerAttrs(peerAttr)
|
||||
testLinkAddDel(t, netkit)
|
||||
}
|
||||
|
||||
func TestLinkAddDelVeth(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
@ -31,6 +31,16 @@ const (
|
||||
IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_NETKIT_UNSPEC = iota
|
||||
IFLA_NETKIT_PEER_INFO
|
||||
IFLA_NETKIT_PRIMARY
|
||||
IFLA_NETKIT_POLICY
|
||||
IFLA_NETKIT_PEER_POLICY
|
||||
IFLA_NETKIT_MODE
|
||||
IFLA_NETKIT_MAX = IFLA_NETKIT_MODE
|
||||
)
|
||||
|
||||
const (
|
||||
VETH_INFO_UNSPEC = iota
|
||||
VETH_INFO_PEER
|
||||
|
Loading…
Reference in New Issue
Block a user