Merge pull request #508 from eyakubovich/mtu

net: add support for MTU config
This commit is contained in:
Eugene Yakubovich
2015-02-09 13:36:00 -08:00
11 changed files with 206 additions and 25 deletions
+1 -1
View File
@@ -70,7 +70,7 @@
},
{
"ImportPath": "github.com/vishvananda/netlink",
"Rev": "7f10b9c2b83cfebb282b60999505e8a72e1231a0"
"Rev": "a59b20a4021ab57ec6a89a4ad5fccfaede1fee77"
},
{
"ImportPath": "golang.org/x/crypto/cast5",
+1 -1
View File
@@ -1,6 +1,6 @@
# netlink - netlink library for go #
[![Build Status](https://travis-ci.org/vishvananda/netlink.png?branch=master)](https://travis-ci.org/vishvananda/netlink)
[![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)
The netlink package provides a simple netlink library for go. Netlink
is the interface a user-space program in linux uses to communicate with
+50
View File
@@ -80,6 +80,48 @@ func LinkSetMTU(link Link, mtu int) error {
return err
}
// LinkSetName sets the name of the link device.
// Equivalent to: `ip link set $link name $name`
func LinkSetName(link Link, name string) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Type = syscall.RTM_SETLINK
msg.Flags = syscall.NLM_F_REQUEST
msg.Index = int32(base.Index)
msg.Change = nl.DEFAULT_CHANGE
req.AddData(msg)
data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name))
req.AddData(data)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
return err
}
// LinkSetHardwareAddr sets the hardware address of the link device.
// Equivalent to: `ip link set $link address $hwaddr`
func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
base := link.Attrs()
ensureIndex(base)
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
msg.Type = syscall.RTM_SETLINK
msg.Flags = syscall.NLM_F_REQUEST
msg.Index = int32(base.Index)
msg.Change = nl.DEFAULT_CHANGE
req.AddData(msg)
data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr))
req.AddData(data)
_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
return err
}
// LinkSetMaster sets the master of the link device.
// Equivalent to: `ip link set $link master $master`
func LinkSetMaster(link Link, master *Bridge) error {
@@ -263,6 +305,11 @@ func LinkAdd(link Link) error {
nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
req.AddData(nameData)
if base.MTU > 0 {
mtu := nl.NewRtAttr(syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
req.AddData(mtu)
}
linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
@@ -279,6 +326,9 @@ func LinkAdd(link Link) error {
nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC)
nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName))
nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
if base.MTU > 0 {
nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
}
} else if vxlan, ok := link.(*Vxlan); ok {
addVxlanAttrs(vxlan, linkInfo)
}
+65 -2
View File
@@ -1,6 +1,8 @@
package netlink
import (
"bytes"
"net"
"testing"
"github.com/vishvananda/netns"
@@ -52,6 +54,9 @@ func testLinkAddDel(t *testing.T, link Link) {
if veth.TxQLen != testTxQLen {
t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, testTxQLen)
}
if rBase.MTU != base.MTU {
t.Fatalf("MTU is %d, should be %d", rBase.MTU, base.MTU)
}
if veth.PeerName != "" {
var peer *Veth
@@ -156,7 +161,7 @@ func TestLinkAddDelBridge(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, &Bridge{LinkAttrs{Name: "foo"}})
testLinkAddDel(t, &Bridge{LinkAttrs{Name: "foo", MTU: 1400}})
}
func TestLinkAddDelVlan(t *testing.T) {
@@ -195,7 +200,7 @@ func TestLinkAddDelVeth(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
testLinkAddDel(t, &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen}, "bar"})
testLinkAddDel(t, &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar"})
}
func TestLinkAddDelBridgeMaster(t *testing.T) {
@@ -399,3 +404,61 @@ func TestLinkByIndex(t *testing.T) {
t.Fatalf("LinkByIndex(%v) found deleted link", err)
}
}
func TestLinkSet(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
iface := &Dummy{LinkAttrs{Name: "foo"}}
if err := LinkAdd(iface); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
err = LinkSetName(link, "bar")
if err != nil {
t.Fatalf("Could not change interface name: %v", err)
}
link, err = LinkByName("bar")
if err != nil {
t.Fatalf("Interface name not changed: %v", err)
}
err = LinkSetMTU(link, 1400)
if err != nil {
t.Fatalf("Could not set MTU: %v", err)
}
link, err = LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if link.Attrs().MTU != 1400 {
t.Fatal("MTU not changed!")
}
addr, err := net.ParseMAC("00:12:34:56:78:AB")
if err != nil {
t.Fatal(err)
}
err = LinkSetHardwareAddr(link, addr)
if err != nil {
t.Fatal(err)
}
link, err = LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(link.Attrs().HardwareAddr, addr) {
t.Fatalf("hardware address not changed!")
}
}
+3
View File
@@ -248,6 +248,9 @@ done:
continue
}
res = append(res, m.Data)
if m.Header.Flags&syscall.NLM_F_MULTI == 0 {
break done
}
}
}
return res, nil
+1 -1
View File
@@ -30,6 +30,6 @@ type Route struct {
}
func (r Route) String() string {
return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s}", r.LinkIndex, r.Dst.String(),
return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s}", r.LinkIndex, r.Dst,
r.Src, r.Gw)
}
+59
View File
@@ -164,3 +164,62 @@ func RouteList(link Link, family int) ([]Route, error) {
return res, nil
}
// RouteGet gets a route to a specific destination from the host system.
// Equivalent to: 'ip route get'.
func RouteGet(destination net.IP) ([]Route, error) {
req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST)
family := nl.GetIPFamily(destination)
var destinationData []byte
var bitlen uint8
if family == FAMILY_V4 {
destinationData = destination.To4()
bitlen = 32
} else {
destinationData = destination.To16()
bitlen = 128
}
msg := &nl.RtMsg{}
msg.Family = uint8(family)
msg.Dst_len = bitlen
req.AddData(msg)
rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData)
req.AddData(rtaDst)
msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
if err != nil {
return nil, err
}
native := nl.NativeEndian()
res := make([]Route, 0)
for _, m := range msgs {
msg := nl.DeserializeRtMsg(m)
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil {
return nil, err
}
route := Route{}
for _, attr := range attrs {
switch attr.Attr.Type {
case syscall.RTA_GATEWAY:
route.Gw = net.IP(attr.Value)
case syscall.RTA_PREFSRC:
route.Src = net.IP(attr.Value)
case syscall.RTA_DST:
route.Dst = &net.IPNet{
IP: attr.Value,
Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
}
case syscall.RTA_OIF:
routeIndex := int(native.Uint32(attr.Value[0:4]))
route.LinkIndex = routeIndex
}
}
res = append(res, route)
}
return res, nil
}
+11 -1
View File
@@ -34,7 +34,17 @@ func TestRouteAddDel(t *testing.T) {
t.Fatal(err)
}
if len(routes) != 1 {
t.Fatal("Link not removed properly")
t.Fatal("Link not added properly")
}
dstIP := net.ParseIP("192.168.0.42")
routeToDstIP, err := RouteGet(dstIP)
if err != nil {
t.Fatal(err)
}
if len(routeToDstIP) == 0 {
t.Fatal("Default route not present")
}
err = RouteDel(&route)
+7 -5
View File
@@ -37,6 +37,7 @@ type Net struct {
BrName string `json:"bridgeName"`
IsGW bool `json:"isGateway"`
IPMasq bool `json:"ipMasq"`
MTU int `json:"mtu"`
}
func init() {
@@ -93,10 +94,11 @@ func bridgeByName(name string) (*netlink.Bridge, error) {
return br, nil
}
func ensureBridge(brName string, ipn *net.IPNet) (*netlink.Bridge, error) {
func ensureBridge(brName string, mtu int, ipn *net.IPNet) (*netlink.Bridge, error) {
br := &netlink.Bridge{
LinkAttrs: netlink.LinkAttrs{
Name: brName,
MTU: mtu,
},
}
@@ -123,12 +125,12 @@ func ensureBridge(brName string, ipn *net.IPNet) (*netlink.Bridge, error) {
return br, nil
}
func setupVeth(contID types.UUID, netns string, br *netlink.Bridge, ifName string, ipConf *ipam.IPConfig) error {
func setupVeth(contID types.UUID, netns string, br *netlink.Bridge, ifName string, mtu int, ipConf *ipam.IPConfig) error {
var hostVethName string
err := util.WithNetNSPath(netns, func(hostNS *os.File) error {
// create the veth pair in the container and move host end into host netns
hostVeth, _, err := util.SetupVeth(contID.String(), ifName, nil, hostNS)
hostVeth, _, err := util.SetupVeth(contID.String(), ifName, mtu, hostNS)
if err != nil {
return err
}
@@ -173,7 +175,7 @@ func setupBridge(n *Net, ipConf *ipam.IPConfig) (*netlink.Bridge, error) {
}
// create bridge if necessary
br, err := ensureBridge(n.BrName, gwn)
br, err := ensureBridge(n.BrName, n.MTU, gwn)
if err != nil {
return nil, fmt.Errorf("failed to create bridge %q: %v", n.BrName, err)
}
@@ -207,7 +209,7 @@ func cmdAdd(contID, netns, netConf, ifName string) error {
return err
}
if err = setupVeth(*cid, netns, br, ifName, ipConf); err != nil {
if err = setupVeth(*cid, netns, br, ifName, n.MTU, ipConf); err != nil {
return err
}
+4 -3
View File
@@ -38,14 +38,15 @@ func init() {
type Net struct {
rktnet.Net
IPMasq bool `json:"ipMasq"`
MTU int `json:"mtu"`
}
func setupContVeth(contID, netns, ifName string, ipConf *ipam.IPConfig) (string, error) {
func setupContVeth(contID, netns, ifName string, mtu int, ipConf *ipam.IPConfig) (string, error) {
var hostVethName string
err := util.WithNetNSPath(netns, func(hostNS *os.File) error {
entropy := contID + ifName
hostVeth, _, err := util.SetupVeth(entropy, ifName, nil, hostNS)
hostVeth, _, err := util.SetupVeth(entropy, ifName, mtu, hostNS)
if err != nil {
return err
}
@@ -99,7 +100,7 @@ func cmdAdd(contID, netns, netConf, ifName, args string) error {
return err
}
hostVethName, err := setupContVeth(contID, netns, ifName, ipConf)
hostVethName, err := setupContVeth(contID, netns, ifName, conf.MTU, ipConf)
if err != nil {
return err
}
+4 -11
View File
@@ -23,11 +23,12 @@ import (
"github.com/coreos/rocket/Godeps/_workspace/src/github.com/vishvananda/netlink"
)
func makeVeth(name, peer string) (netlink.Link, error) {
func makeVeth(name, peer string, mtu int) (netlink.Link, error) {
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{
Name: name,
Flags: net.FlagUp,
MTU: mtu,
},
PeerName: peer,
}
@@ -47,10 +48,10 @@ func hash(s string) string {
// SetupVeth sets up a virtual ethernet link.
// Should be in container netns.
// TODO(eyakubovich): get rid of entropy and ask kernel to pick name via pattern
func SetupVeth(entropy, contVethName string, ipn *net.IPNet, hostNS *os.File) (hostVeth, contVeth netlink.Link, err error) {
func SetupVeth(entropy, contVethName string, mtu int, hostNS *os.File) (hostVeth, contVeth netlink.Link, err error) {
// NetworkManager (recent versions) will ignore veth devices that start with "veth"
hostVethName := "veth" + hash(entropy)[:4]
hostVeth, err = makeVeth(hostVethName, contVethName)
hostVeth, err = makeVeth(hostVethName, contVethName, mtu)
if err != nil {
err = fmt.Errorf("failed to make veth pair: %v", err)
return
@@ -72,14 +73,6 @@ func SetupVeth(entropy, contVethName string, ipn *net.IPNet, hostNS *os.File) (h
return
}
if ipn != nil {
addr := &netlink.Addr{IPNet: ipn, Label: ""}
if err = netlink.AddrAdd(contVeth, addr); err != nil {
err = fmt.Errorf("failed to add IP addr to veth: %v", err)
return
}
}
if err = netlink.LinkSetNsFd(hostVeth, int(hostNS.Fd())); err != nil {
err = fmt.Errorf("failed to move veth to host netns: %v", err)
return