Move attach() and detach() from shell script to Go

This commit is contained in:
Bryan Boreham committed 2016-05-25 17:34:13 +01:00
1 parent e3ef473cd3
commit ac14b19db8
5 files changed
+155 -81

No files matched your search

+76 -10
View File
@@ -85,14 +85,30 @@ func SetupGuest(guest netlink.Link, name string) error {
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)
func AddAddresses(guest netlink.Link, cidrs []*net.IPNet) (newAddrs []*net.IPNet, err error) {
existingAddrs, err := netlink.AddrList(guest, netlink.FAMILY_V4)
if err != nil {
return nil, fmt.Errorf("failed to get IP address for %q: %v", guest.Attrs().Name, err)
}
return nil
for _, ipnet := range cidrs {
if contains(existingAddrs, ipnet) {
continue
}
if err := netlink.AddrAdd(guest, &netlink.Addr{IPNet: ipnet}); err != nil {
return nil, fmt.Errorf("failed to add IP address to %q: %v", guest.Attrs().Name, err)
}
newAddrs = append(newAddrs, ipnet)
}
return newAddrs, nil
}
func contains(addrs []netlink.Addr, addr *net.IPNet) bool {
for _, x := range addrs {
if addr.IP.Equal(x.IPNet.IP) {
return true
}
}
return false
}
func interfaceExistsInNamespace(ns netns.NsHandle, ifName string) bool {
@@ -103,13 +119,14 @@ func interfaceExistsInNamespace(ns netns.NsHandle, ifName string) bool {
return err == nil
}
func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, cidrs []*net.IPNet) error {
func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, withMulticastRoute bool, 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 {
EthtoolTXOff(peerName) // TODO: do we want to do this under fastdp?
if err := netlink.LinkSetNsFd(guest, int(ns)); err != nil {
return fmt.Errorf("failed to move veth to container netns: %s", err)
}
@@ -126,13 +143,62 @@ func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int,
}
if err := WithNetNSLink(ns, ifName, func(guest netlink.Link) error {
if err := AddAddresses(guest, cidrs); err != nil {
newAddresses, err := AddAddresses(guest, cidrs)
if err != nil {
return err
}
return netlink.LinkSetUp(guest)
if err := netlink.LinkSetUp(guest); err != nil {
return err
}
for _, ipnet := range newAddresses {
arping.GratuitousArpOverIfaceByName(ipnet.IP, ifName)
}
if withMulticastRoute {
/* Route multicast packets across the weave network.
This must come last in 'attach'. If you change this, change weavewait to match.
TODO: Add the MTU lock to prevent PMTU discovery for multicast
destinations. Without that, the kernel sets the DF flag on
multicast packets. Since RFC1122 prohibits sending of ICMP
errors for packets with multicast destinations, that causes
packets larger than the PMTU to be dropped silently. */
_, multicast, _ := net.ParseCIDR("224.0.0.0/4")
if err := AddRoute(guest, netlink.SCOPE_LINK, multicast, nil); err != nil {
return err
}
}
return nil
}); err != nil {
return err
}
return nil
}
func DetachContainer(ns netns.NsHandle, id, ifName string, cidrs []*net.IPNet) error {
return WithNetNSLink(ns, ifName, func(guest netlink.Link) error {
existingAddrs, err := netlink.AddrList(guest, netlink.FAMILY_V4)
if err != nil {
return fmt.Errorf("failed to get IP address for %q: %v", guest.Attrs().Name, err)
}
for _, ipnet := range cidrs {
if !contains(existingAddrs, ipnet) {
continue
}
if err := netlink.AddrDel(guest, &netlink.Addr{IPNet: ipnet}); err != nil {
return fmt.Errorf("failed to remove IP address from %q: %v", guest.Attrs().Name, err)
}
}
addrs, err := netlink.AddrList(guest, netlink.FAMILY_V4)
if err != nil {
return fmt.Errorf("failed to get IP address for %q: %v", guest.Attrs().Name, err)
}
if len(addrs) == 0 { // all addresses gone: remove the interface
if err := netlink.LinkDel(guest); err != nil {
return err
}
}
return nil
})
}
+1 -1
View File
@@ -92,7 +92,7 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
id = fmt.Sprintf("%x", data)
}
if err := weavenet.AttachContainer(ns, id, args.IfName, conf.BrName, conf.MTU, []*net.IPNet{&result.IP4.IP}); err != nil {
if err := weavenet.AttachContainer(ns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&result.IP4.IP}); err != nil {
return err
}
if err := weavenet.WithNetNSLink(ns, args.IfName, func(guest netlink.Link) error {
+72
View File
@@ -0,0 +1,72 @@
package main
import (
"net"
"strconv"
"github.com/vishvananda/netns"
weavenet "github.com/weaveworks/weave/net"
)
func attach(args []string) error {
if len(args) < 4 {
cmdUsage("attach-container", "[--no-multicast-route] <pid> <bridge-name> <mtu> <cidr>...")
}
withMulticastRoute := true
if args[0] == "--no-multicast-route" {
withMulticastRoute = false
args = args[1:]
}
pid, err := strconv.Atoi(args[0])
if err != nil {
return err
}
ns, err := netns.GetFromPid(pid)
if err != nil {
return err
}
mtu, err := strconv.Atoi(args[2])
if err != nil && args[3] != "" {
return err
}
cidrs, err := parseCIDRs(args[3:])
if err != nil {
return err
}
return weavenet.AttachContainer(ns, args[0], "ethwe", args[1], mtu, withMulticastRoute, cidrs)
}
func parseCIDRs(args []string) (cidrs []*net.IPNet, err error) {
for _, ipstr := range args {
ip, ipnet, err := net.ParseCIDR(ipstr)
if err != nil {
return nil, err
}
ipnet.IP = ip // we want the specific IP plus the mask
cidrs = append(cidrs, ipnet)
}
return
}
func detach(args []string) error {
if len(args) < 2 {
cmdUsage("detach-container", "<pid> <cidr>...")
}
pid, err := strconv.Atoi(args[0])
if err != nil {
return err
}
ns, err := netns.GetFromPid(pid)
if err != nil {
return err
}
cidrs, err := parseCIDRs(args[1:])
if err != nil {
return err
}
return weavenet.DetachContainer(ns, args[0], "ethwe", cidrs)
}
+2
View File
@@ -19,6 +19,8 @@ func init() {
"create-plugin-network": createPluginNetwork,
"remove-plugin-network": removePluginNetwork,
"container-addrs": containerAddrs,
"attach-container": attach,
"detach-container": detach,
}
}
+4 -70
View File
@@ -847,26 +847,6 @@ netnsenter() {
nsenter --net=$CONTAINER_NETNS "$@"
}
# connect_container_to_bridge <container interface name>
connect_container_to_bridge() {
ip link add name $LOCAL_IFNAME mtu $MTU type veth peer name $GUEST_IFNAME mtu $MTU || return 1
if ! ethtool_tx_off_$BRIDGE_TYPE $GUEST_IFNAME ||
! ip link set $GUEST_IFNAME netns $CONTAINER_NETNS ; then
# failed before we assigned the veth to the container's
# namespace
ip link del $LOCAL_IFNAME type veth || true
return 1
fi
if ! netnsenter ip link set $GUEST_IFNAME name $1 ||
! ip link set $LOCAL_IFNAME up ||
! add_iface_$BRIDGE_TYPE $LOCAL_IFNAME ||
! configure_arp_cache $1 "netnsenter" ; then
return 1
fi
}
add_iface_fastdp() {
util_op add-datapath-interface $DATAPATH $1
}
@@ -940,59 +920,13 @@ attach() {
return 1
fi
if ! netnsenter ip link show $CONTAINER_IFNAME >/dev/null 2>&1 ; then
connect_container_to_bridge $CONTAINER_IFNAME || return 1
fi
NEW_ADDRS=
for ADDR in "$@" ; do
if netnsenter ip addr show dev $CONTAINER_IFNAME | grep -F $ADDR >/dev/null ; then
# address was there already
continue
fi
netnsenter ip addr add $ADDR dev $CONTAINER_IFNAME || return 1
NEW_ADDRS="$NEW_ADDRS $ADDR"
done
netnsenter ip link set $CONTAINER_IFNAME up || return 1
for ADDR in $NEW_ADDRS ; do
arp_update $CONTAINER_IFNAME $ADDR "netnsenter" || true
done
# Route multicast packets across the weave network.
# This must come last in 'attach'. If you change this, change weavewait to match.
#
# The MTU lock prevents PMTU discovery for multicast
# destinations. Without that, the kernel sets the DF flag on
# multicast packets. Since RFC1122 prohibits sending of ICMP
# errors for packets with multicast destinations, that causes
# packets larger than the PMTU to be dropped silently.
if [ -z "$NO_MULTICAST_ROUTE" ] ; then
if ! netnsenter ip route show | grep '^224\.0\.0\.0/4' >/dev/null ; then
netnsenter ip route add 224.0.0.0/4 dev $CONTAINER_IFNAME mtu lock $MTU
fi
fi
ATTACH_ARGS=""
[ -n "$NO_MULTICAST_ROUTE" ] && ATTACH_ARGS="--no-multicast-route"
util_op attach-container $ATTACH_ARGS $CONTAINER_PID $BRIDGE $MTU "$@"
}
detach() {
netnsenter ip link show $CONTAINER_IFNAME >/dev/null 2>&1 || return 0
for ADDR in "$@" ; do
if ! netnsenter ip addr show dev $CONTAINER_IFNAME | grep -F $ADDR >/dev/null ; then
# address is not there, leave the device alone
continue
fi
netnsenter ip addr del $ADDR dev $CONTAINER_IFNAME || return 1
done
if [ -n "$(netnsenter ip -f inet addr show dev $CONTAINER_IFNAME)" ] ; then
# other addresses are left, leave the device alone
return 0
fi
# Deleting the interface will delete the multicast route we set up
netnsenter ip link del $CONTAINER_IFNAME type veth
util_op detach-container $CONTAINER_PID "$@"
}
######################################################################