diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index effda7b..51f2088 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -70,7 +70,7 @@ }, { "ImportPath": "github.com/vishvananda/netlink", - "Rev": "7f10b9c2b83cfebb282b60999505e8a72e1231a0" + "Rev": "a59b20a4021ab57ec6a89a4ad5fccfaede1fee77" }, { "ImportPath": "golang.org/x/crypto/cast5", diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md b/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md index 366c364..555f886 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md @@ -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 diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go index e39452d..20497dd 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go @@ -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) } diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go index 232ad03..831684c 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go @@ -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!") + } +} diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go index 9c2499e..72f2813 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go @@ -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 diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go index e92a9cf..6218546 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go @@ -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) } diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go index 804e3e9..3e4b6cc 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go @@ -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 + +} diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/route_test.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/route_test.go index c1cc16d..7f8d42c 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/route_test.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/route_test.go @@ -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) diff --git a/networking/net/bridge/bridge.go b/networking/net/bridge/bridge.go index 2dd6a8e..46b91fa 100644 --- a/networking/net/bridge/bridge.go +++ b/networking/net/bridge/bridge.go @@ -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 } diff --git a/networking/net/veth/veth.go b/networking/net/veth/veth.go index 6e4218d..1ab1f6d 100644 --- a/networking/net/veth/veth.go +++ b/networking/net/veth/veth.go @@ -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 } diff --git a/networking/util/link.go b/networking/util/link.go index 72877f8..2fb5ae6 100644 --- a/networking/util/link.go +++ b/networking/util/link.go @@ -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