Files
weave/net/veth.go
T
Bryan Boreham 85023e0a76 Extract AttachContainer() function
Also move netlink and netns code from common to net

Creates interface if not already there
Adds addresses
Move the set link 'up' to after addresses are added
2016-05-25 17:29:45 +01:00

139 lines
3.9 KiB
Go

package net
import (
"fmt"
"net"
"github.com/j-keck/arping"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
"github.com/weaveworks/weave/common/odp"
)
// create and attach local name to the Weave bridge
func CreateAndAttachVeth(localName, peerName, bridgeName string, mtu int, init func(local, guest netlink.Link) error) (*netlink.Veth, error) {
maybeBridge, err := netlink.LinkByName(bridgeName)
if err != nil {
return nil, fmt.Errorf(`bridge "%s" not present; did you launch weave?`, bridgeName)
}
if mtu == 0 {
mtu = maybeBridge.Attrs().MTU
}
local := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{
Name: localName,
MTU: mtu},
PeerName: peerName,
}
if err := netlink.LinkAdd(local); err != nil {
return nil, fmt.Errorf(`could not create veth pair %s-%s: %s`, local.Name, local.PeerName, err)
}
cleanup := func(format string, a ...interface{}) (*netlink.Veth, error) {
netlink.LinkDel(local)
return nil, fmt.Errorf(format, a...)
}
switch maybeBridge.(type) {
case *netlink.Bridge:
if err := netlink.LinkSetMasterByIndex(local, maybeBridge.Attrs().Index); err != nil {
return cleanup(`unable to set master of %s: %s`, local.Name, err)
}
case *netlink.GenericLink:
if maybeBridge.Type() != "openvswitch" {
return cleanup(`device "%s" is of type "%s"`, bridgeName, maybeBridge.Type())
}
if err := odp.AddDatapathInterface(bridgeName, local.Name); err != nil {
return cleanup(`failed to attach %s to device "%s": %s`, local.Name, bridgeName, err)
}
case *netlink.Device:
// Assume it's our openvswitch device, and the kernel has not been updated to report the kind.
if err := odp.AddDatapathInterface(bridgeName, local.Name); err != nil {
return cleanup(`failed to attach %s to device "%s": %s`, local.Name, bridgeName, err)
}
default:
return cleanup(`device "%s" is not a bridge`, bridgeName)
}
if init != nil {
guest, err := netlink.LinkByName(peerName)
if err != nil {
return cleanup("unable to find guest veth %s: %s", peerName, err)
}
if err := init(local, guest); err != nil {
return cleanup("initializing veth: %s", err)
}
}
if err := netlink.LinkSetUp(local); err != nil {
return cleanup("unable to bring veth up: %s", err)
}
return local, nil
}
func SetupGuest(guest netlink.Link, name string) error {
var err error
if err = netlink.LinkSetName(guest, name); err != nil {
return err
}
if err = ConfigureARPCache(name); err != nil {
return err
}
return nil
}
func AddAddresses(guest netlink.Link, cidrs []*net.IPNet) error {
for _, ipnet := range cidrs {
if err := netlink.AddrAdd(guest, &netlink.Addr{IPNet: ipnet}); err != nil {
return fmt.Errorf("failed to add IP address to %q: %v", guest.Attrs().Name, err)
}
arping.GratuitousArpOverIfaceByName(ipnet.IP, guest.Attrs().Name)
}
return nil
}
func interfaceExistsInNamespace(ns netns.NsHandle, ifName string) bool {
err := WithNetNS(ns, func() error {
_, err := netlink.LinkByName(ifName)
return err
})
return err == nil
}
func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, cidrs []*net.IPNet) error {
if !interfaceExistsInNamespace(ns, ifName) {
if len(id) > 5 {
id = id[:5]
}
name, peerName := "vethwepl"+id, "vethwg"+id
_, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, func(local, guest netlink.Link) error {
if err := netlink.LinkSetNsFd(guest, int(ns)); err != nil {
return fmt.Errorf("failed to move veth to container netns: %s", err)
}
if err := WithNetNS(ns, func() error {
return SetupGuest(guest, ifName)
}); err != nil {
return fmt.Errorf("error setting up interface: %s", err)
}
return nil
})
if err != nil {
return err
}
}
if err := WithNetNSLink(ns, ifName, func(guest netlink.Link) error {
if err := AddAddresses(guest, cidrs); err != nil {
return err
}
return netlink.LinkSetUp(guest)
}); err != nil {
return err
}
return nil
}