-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds Netkit and Veth drivers. Signed-off-by: Birol Bilgin <birolbilgin@gmail.com>
- Loading branch information
Showing
7 changed files
with
453 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package driver | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/jsimonetti/rtnetlink" | ||
"github.com/jsimonetti/rtnetlink/internal/unix" | ||
"github.com/mdlayher/netlink" | ||
) | ||
|
||
// NetkitMode specifies netkit operation mode | ||
type NetkitMode uint32 | ||
|
||
func (n NetkitMode) String() string { | ||
switch n { | ||
case NetkitModeL2: | ||
return "layer2" | ||
case NetkitModeL3: | ||
return "layer3" | ||
default: | ||
return fmt.Sprintf("unknown NetkitMode value (%d)", n) | ||
} | ||
} | ||
|
||
const ( | ||
// Netkit operates on layer2 | ||
NetkitModeL2 NetkitMode = unix.NETKIT_L2 | ||
|
||
// Netkit operates on layer3, this is the default mode | ||
NetkitModeL3 NetkitMode = unix.NETKIT_L3 | ||
) | ||
|
||
// NetkitPolicy specifies default packet policy when no eBPF program is attached | ||
type NetkitPolicy int32 | ||
|
||
func (n NetkitPolicy) String() string { | ||
switch n { | ||
case NetkitPolicyPass: | ||
return "forward" | ||
case NetkitPolicyDrop: | ||
return "blackhole" | ||
default: | ||
return fmt.Sprintf("unknown NetkitPolicy value (%d)", n) | ||
} | ||
} | ||
|
||
const ( | ||
// Default policy to forwards packets | ||
NetkitPolicyPass NetkitPolicy = unix.NETKIT_PASS | ||
|
||
// Default policy to drops packets | ||
NetkitPolicyDrop NetkitPolicy = unix.NETKIT_DROP | ||
) | ||
|
||
// Netkit implements LinkDriverVerifier for the netkit driver | ||
type Netkit struct { | ||
Mode *NetkitMode // Specifies driver operation mode | ||
Policy *NetkitPolicy // Specifies default policy | ||
PeerPolicy *NetkitPolicy // Specifies default peer policy | ||
Primary bool // Shows primary link | ||
PeerInfo *rtnetlink.LinkMessage // Specifies peer link information | ||
} | ||
|
||
var _ rtnetlink.LinkDriverVerifier = &Netkit{} | ||
|
||
func (n *Netkit) New() rtnetlink.LinkDriver { | ||
return &Netkit{} | ||
} | ||
|
||
func (n *Netkit) Verify(msg *rtnetlink.LinkMessage) error { | ||
if msg.Attributes.Address != nil || (n.PeerInfo != nil && n.PeerInfo.Attributes != nil && n.PeerInfo.Attributes.Address != nil) { | ||
return errors.New("netkit does not support setting Ethernet address") | ||
} | ||
return nil | ||
} | ||
|
||
func (n *Netkit) Decode(ad *netlink.AttributeDecoder) error { | ||
for ad.Next() { | ||
switch ad.Type() { | ||
case unix.IFLA_NETKIT_MODE: | ||
v := NetkitMode(ad.Uint32()) | ||
n.Mode = &v | ||
case unix.IFLA_NETKIT_POLICY: | ||
v := NetkitPolicy(ad.Int32()) | ||
n.Policy = &v | ||
case unix.IFLA_NETKIT_PEER_POLICY: | ||
v := NetkitPolicy(ad.Int32()) | ||
n.PeerPolicy = &v | ||
case unix.IFLA_NETKIT_PRIMARY: | ||
n.Primary = ad.Uint8() != 0 | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (n *Netkit) Encode(ae *netlink.AttributeEncoder) error { | ||
if n.Mode != nil { | ||
ae.Uint32(unix.IFLA_NETKIT_MODE, uint32(*n.Mode)) | ||
} | ||
if n.Policy != nil { | ||
ae.Int32(unix.IFLA_NETKIT_POLICY, int32(*n.Policy)) | ||
} | ||
if n.PeerPolicy != nil { | ||
ae.Int32(unix.IFLA_NETKIT_PEER_POLICY, int32(*n.PeerPolicy)) | ||
} | ||
if n.PeerInfo != nil { | ||
b, err := n.PeerInfo.MarshalBinary() | ||
if err != nil { | ||
return err | ||
} | ||
ae.Bytes(unix.IFLA_NETKIT_PEER_INFO, b) | ||
} | ||
return nil | ||
} | ||
|
||
func (n *Netkit) Kind() string { | ||
return "netkit" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
//go:build integration | ||
// +build integration | ||
|
||
package driver | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"github.com/jsimonetti/rtnetlink" | ||
"github.com/mdlayher/netlink" | ||
) | ||
|
||
func TestNetkit(t *testing.T) { | ||
kernelMinReq(t, 6, 7) | ||
|
||
// establish a netlink connection | ||
conn, err := rtnetlink.Dial(nil) | ||
if err != nil { | ||
t.Fatalf("failed to establish netlink socket: %v", err) | ||
} | ||
defer conn.Close() | ||
|
||
// create netns | ||
nkns, clean, err := createNS("nkns1") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer clean() | ||
|
||
// establish a netlink connection with netns | ||
connNS, err := rtnetlink.Dial(&netlink.Config{NetNS: int(nkns.Value())}) | ||
if err != nil { | ||
t.Fatalf("failed to establish netlink socket to ns nkns: %v", err) | ||
} | ||
defer connNS.Close() | ||
|
||
const ( | ||
ifIndex = 1011 | ||
ifPeerIndex = 1012 | ||
) | ||
|
||
modeL2 := NetkitModeL2 | ||
modeL3 := NetkitModeL3 | ||
polPass := NetkitPolicyPass | ||
polDrop := NetkitPolicyDrop | ||
|
||
tests := []struct { | ||
name string | ||
linkName string | ||
pconn *rtnetlink.Conn | ||
driver *Netkit | ||
primary *Netkit | ||
peer *Netkit | ||
}{ | ||
{ | ||
name: "with empty link names both in default ns", | ||
linkName: "", | ||
pconn: conn, | ||
driver: &Netkit{ | ||
PeerInfo: &rtnetlink.LinkMessage{ | ||
Index: ifPeerIndex, | ||
}, | ||
}, | ||
primary: &Netkit{ | ||
Mode: &modeL3, | ||
Policy: &polPass, | ||
PeerPolicy: &polPass, | ||
Primary: true, | ||
}, | ||
peer: &Netkit{ | ||
Mode: &modeL3, | ||
Policy: &polPass, | ||
PeerPolicy: &polPass, | ||
}, | ||
}, | ||
{ | ||
name: "with names both in default ns", | ||
linkName: "nkp", | ||
pconn: conn, | ||
driver: &Netkit{ | ||
Mode: &modeL2, | ||
PeerInfo: &rtnetlink.LinkMessage{ | ||
Index: ifPeerIndex, | ||
Attributes: &rtnetlink.LinkAttributes{ | ||
Name: "nke", | ||
}, | ||
}, | ||
}, | ||
primary: &Netkit{ | ||
Mode: &modeL2, | ||
Policy: &polPass, | ||
PeerPolicy: &polPass, | ||
Primary: true, | ||
}, | ||
peer: &Netkit{ | ||
Mode: &modeL2, | ||
Policy: &polPass, | ||
PeerPolicy: &polPass, | ||
}, | ||
}, | ||
{ | ||
name: "with one is in other ns", | ||
linkName: "nkp", | ||
pconn: connNS, | ||
driver: &Netkit{ | ||
Policy: &polPass, | ||
PeerPolicy: &polDrop, | ||
PeerInfo: &rtnetlink.LinkMessage{ | ||
Index: ifPeerIndex, | ||
Attributes: &rtnetlink.LinkAttributes{ | ||
Name: "nke", | ||
NetNS: nkns, | ||
}, | ||
}, | ||
}, | ||
primary: &Netkit{ | ||
Mode: &modeL3, | ||
Policy: &polPass, | ||
PeerPolicy: &polDrop, | ||
Primary: true, | ||
}, | ||
peer: &Netkit{ | ||
Mode: &modeL3, | ||
Policy: &polDrop, | ||
PeerPolicy: &polPass, | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if err := setupInterface(conn, tt.linkName, ifIndex, 0, tt.driver); err != nil { | ||
t.Fatalf("failed to setup netkit interface: %v", err) | ||
} | ||
defer conn.Link.Delete(ifIndex) | ||
|
||
msg, err := getInterface(conn, ifIndex) | ||
if err != nil { | ||
t.Fatalf("failed to get primary netkit interface: %v", err) | ||
} | ||
if diff := cmp.Diff(tt.primary, msg.Attributes.Info.Data); diff != "" { | ||
t.Error(diff) | ||
} | ||
|
||
msg, err = getInterface(tt.pconn, ifPeerIndex) | ||
if err != nil { | ||
t.Fatalf("failed to get peer netkit interface: %v", err) | ||
} | ||
if diff := cmp.Diff(tt.peer, msg.Attributes.Info.Data); diff != "" { | ||
t.Error(diff) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package driver | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/jsimonetti/rtnetlink" | ||
"github.com/mdlayher/netlink" | ||
) | ||
|
||
const veth_info_peer = 0x1 | ||
|
||
// Veth implements LinkDriverVerifier for the veth driver | ||
type Veth struct { | ||
PeerInfo *rtnetlink.LinkMessage // Specifies peer link information | ||
} | ||
|
||
var _ rtnetlink.LinkDriverVerifier = &Veth{} | ||
|
||
func (v *Veth) New() rtnetlink.LinkDriver { | ||
return &Veth{} | ||
} | ||
|
||
func (v *Veth) Encode(ae *netlink.AttributeEncoder) error { | ||
b, err := v.PeerInfo.MarshalBinary() | ||
if err != nil { | ||
return err | ||
} | ||
ae.Bytes(veth_info_peer, b) | ||
|
||
return nil | ||
} | ||
|
||
func (v *Veth) Decode(ad *netlink.AttributeDecoder) error { | ||
return nil | ||
} | ||
|
||
func (*Veth) Kind() string { | ||
return "veth" | ||
} | ||
|
||
const ( | ||
eth_min_mtu = 68 // Min IPv4 MTU per RFC791 | ||
eth_max_mtu = 65535 // 65535, same as IP_MAX_MTU | ||
) | ||
|
||
func (v *Veth) Verify(msg *rtnetlink.LinkMessage) error { | ||
if msg.Attributes != nil && msg.Attributes.MTU > 0 && (msg.Attributes.MTU < eth_min_mtu || msg.Attributes.MTU > eth_max_mtu) { | ||
return fmt.Errorf("invalid MTU value %d, must be between %d %d", msg.Attributes.MTU, eth_min_mtu, eth_max_mtu) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.