Move attach() and detach() from shell script to Go
This commit is contained in:
1 parent
e3ef473cd3
commit
ac14b19db8
5 files changed
+155
-81
No files matched your search
+76
-10
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -19,6 +19,8 @@ func init() {
|
||||
"create-plugin-network": createPluginNetwork,
|
||||
"remove-plugin-network": removePluginNetwork,
|
||||
"container-addrs": containerAddrs,
|
||||
"attach-container": attach,
|
||||
"detach-container": detach,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 "$@"
|
||||
}
|
||||
|
||||
######################################################################
|
||||
|
||||
Reference in new issue
Block a user