diff --git a/net/bridge.go b/net/bridge.go index f5e89587..a88a7334 100644 --- a/net/bridge.go +++ b/net/bridge.go @@ -28,6 +28,23 @@ const ( Inconsistent ) +// Returns a string that is consistent with the weave script +func (t BridgeType) String() string { + switch t { + case None: + return "none" + case Bridge: + return "bridge" + case Fastdp: + return "fastdp" + case BridgedFastdp: + return "bridged_fastdp" + case Inconsistent: + return "inconsistent" + } + return "unknown" +} + func DetectBridgeType(weaveBridgeName, datapathName string) BridgeType { bridge, _ := netlink.LinkByName(weaveBridgeName) datapath, _ := netlink.LinkByName(datapathName) @@ -151,8 +168,6 @@ func FindBridgeIP(bridgeName string, subnet *net.IPNet) (net.IP, error) { } type BridgeConfig struct { - DBPrefix string - HostRoot string DockerBridgeName string WeaveBridgeName string DatapathName string diff --git a/prog/weaveutil/bridge.go b/prog/weaveutil/bridge.go new file mode 100644 index 00000000..b82f8fdb --- /dev/null +++ b/prog/weaveutil/bridge.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + "strconv" + + weavenet "github.com/weaveworks/weave/net" +) + +func detectBridgeType(args []string) error { + if len(args) != 2 { + cmdUsage("detect-bridge-type", " ") + } + bridgeType := weavenet.DetectBridgeType(args[0], args[1]) + fmt.Println(bridgeType.String()) + return nil +} + +func createBridge(args []string) error { + if len(args) != 8 { + cmdUsage("create-bridge", " ") + } + + mtu, err := strconv.Atoi(args[3]) + if err != nil && args[3] != "" { + return err + } + port, err := strconv.Atoi(args[4]) + if err != nil { + return err + } + config := weavenet.BridgeConfig{ + DockerBridgeName: args[0], + WeaveBridgeName: args[1], + DatapathName: args[2], + MTU: mtu, + Port: port, + Mac: args[5], + NoFastdp: args[6] != "", + NoBridgedFastdp: args[7] != "", + } + bridgeType, err := weavenet.CreateBridge(&config) + fmt.Println(bridgeType.String()) + return err +} diff --git a/prog/weaveutil/datapath.go b/prog/weaveutil/datapath.go index 52e320f8..f4494967 100644 --- a/prog/weaveutil/datapath.go +++ b/prog/weaveutil/datapath.go @@ -31,19 +31,6 @@ func deleteDatapath(args []string) error { return odp.DeleteDatapath(args[0]) } -// Checks whether a datapath can be created by actually creating and destroying it -func checkDatapath(args []string) error { - if len(args) != 1 { - cmdUsage("check-datapath", "") - } - - if err := createDatapath(args); err != nil { - return err - } - - return odp.DeleteDatapath(args[0]) -} - func addDatapathInterface(args []string) error { if len(args) != 2 { cmdUsage("add-datapath-interface", " ") diff --git a/prog/weaveutil/main.go b/prog/weaveutil/main.go index bc954761..46ffa719 100644 --- a/prog/weaveutil/main.go +++ b/prog/weaveutil/main.go @@ -17,9 +17,10 @@ func init() { "help": help, "netcheck": netcheck, "docker-tls-args": dockerTLSArgs, + "create-bridge": createBridge, + "detect-bridge-type": detectBridgeType, "create-datapath": createDatapath, "delete-datapath": deleteDatapath, - "check-datapath": checkDatapath, "add-datapath-interface": addDatapathInterface, "create-plugin-network": createPluginNetwork, "remove-plugin-network": removePluginNetwork, diff --git a/weave b/weave index 7349989a..0f053d3f 100755 --- a/weave +++ b/weave @@ -365,15 +365,6 @@ delete_iptables_rule() { fi } -# Configure the ARP cache parameters for the given interface. This -# makes containers react more quickly to a change in the MAC address -# associated with an IP address. -configure_arp_cache() { - $2 sh -c "echo 5 >$PROC_PATH/sys/net/ipv4/neigh/$1/base_reachable_time && - echo 2 >$PROC_PATH/sys/net/ipv4/neigh/$1/delay_first_probe_time && - echo 1 >$PROC_PATH/sys/net/ipv4/neigh/$1/ucast_solicit" -} - # Send out an ARP announcement # (https://tools.ietf.org/html/rfc5227#page-15) to update ARP cache # entries across the weave network. We do this in addition to @@ -449,29 +440,21 @@ enforce_docker_bridge_addr_assign_type() { # bridge/datapath devices have yet to be configured. If netdevs do exist # but are in an inconsistent state the script aborts with an error. detect_bridge_type() { - BRIDGE_TYPE= - if [ -d /sys/class/net/$DATAPATH ] ; then - # Unfortunately there's no simple way to positively check whether - # $DATAPATH is an ODP netdev so we have to make sure it isn't - # a bridge instead (and that $BRIDGE is). - if [ ! -d /sys/class/net/$DATAPATH/bridge -a -d /sys/class/net/$BRIDGE/bridge ] ; then - BRIDGE_TYPE=bridged_fastdp - else + BRIDGE_TYPE=$(util_op detect-bridge-type "$BRIDGE" "$DATAPATH") + case "$BRIDGE_TYPE" in + bridge|bridged_fastdp) + ;; + fastdp) + DATAPATH="$BRIDGE" + ;; + inconsistent) echo "Inconsistent bridge state detected. Please do 'weave reset' and try again." >&2 exit 1 - fi - elif [ -d /sys/class/net/$BRIDGE ] ; then - if [ -d /sys/class/net/$BRIDGE/bridge ] ; then - BRIDGE_TYPE=bridge - else - BRIDGE_TYPE=fastdp - # The datapath is the bridge when there is no intermediary - DATAPATH="$BRIDGE" - fi - else - # No bridge/datapath devices configured - return 1 - fi + ;; + *) + return 1 + ;; + esac # WEAVE_MTU may have been specified when the bridge was # created (perhaps implicitly with WEAVE_NO_FASTDP). So take @@ -481,46 +464,19 @@ detect_bridge_type() { } try_create_bridge() { - if ! detect_bridge_type ; then - BRIDGE_TYPE=bridge - if [ -z "$WEAVE_NO_FASTDP" ] ; then - BRIDGE_TYPE=bridged_fastdp - if [ -n "$WEAVE_NO_BRIDGED_FASTDP" ] ; then - BRIDGE_TYPE=fastdp - # The datapath is the bridge when there is no intermediary - DATAPATH="$BRIDGE" - fi - if util_op create-datapath $DATAPATH ; then - : # ODP datapath created successfully - elif [ $? = 17 ] ; then - # Exit status of 17 means the kernel doesn't have ODP - BRIDGE_TYPE=bridge - else - return 1 - fi - fi + # Running this from 'weave --local' when weaveexec is not on the + # path will run it as a Docker container that does not have access + # to /etc/machine-id, so will not give the full range of persistent IDs + if [ -z "$WEAVEDB_DIR_PATH" ]; then + WEAVEDB_DIR_PATH="$HOST_ROOT/$(docker inspect -f '{{with index .Mounts 0}}{{.Source}}{{end}}' $DB_CONTAINER_NAME 2>/dev/null)" + fi + MAC=$(util_op unique-id "$WEAVEDB_DIR_PATH/weave" "$HOST_ROOT") + BRIDGE_TYPE=$(util_op create-bridge "$DOCKER_BRIDGE" "$BRIDGE" "$DATAPATH" "$WEAVE_MTU" "$PORT" "$MAC" "$WEAVE_NO_FASTDP" "$WEAVE_NO_BRIDGED_FASTDP") + # Set some variables that are expected by code that comes later + [ "$BRIDGE_TYPE" != "fastdp" ] || DATAPATH="$BRIDGE" + MTU=${WEAVE_MTU:-$(cat /sys/class/net/$BRIDGE/mtu)} - init_$BRIDGE_TYPE - - # Drop traffic from Docker bridge to Weave; it can break - # subnet isolation - if [ "$DOCKER_BRIDGE" != "$BRIDGE" ] ; then - # Note using -I to insert ahead of Docker's bridge rules - run_iptables -t filter -I FORWARD -i $DOCKER_BRIDGE -o $BRIDGE -j DROP - fi - - [ -n "$DOCKER_BRIDGE_IP" ] || DOCKER_BRIDGE_IP=$(util_op bridge-ip $DOCKER_BRIDGE) - - # forbid traffic to the Weave port from other containers - add_iptables_rule filter INPUT -i $DOCKER_BRIDGE -p tcp --dst $DOCKER_BRIDGE_IP --dport $PORT -j DROP - add_iptables_rule filter INPUT -i $DOCKER_BRIDGE -p udp --dst $DOCKER_BRIDGE_IP --dport $PORT -j DROP - add_iptables_rule filter INPUT -i $DOCKER_BRIDGE -p udp --dst $DOCKER_BRIDGE_IP --dport $(($PORT + 1)) -j DROP - - # let DNS traffic to weaveDNS, since otherwise it might get blocked by the likes of UFW - add_iptables_rule filter INPUT -i $DOCKER_BRIDGE -p udp --dport 53 -j ACCEPT - add_iptables_rule filter INPUT -i $DOCKER_BRIDGE -p tcp --dport 53 -j ACCEPT - - if [ "$2" = "--expect-npc" ] ; then # matches usage in weave-kube launch.sh + if [ "$1" = "--expect-npc" ] ; then # matches usage in weave-kube launch.sh # Steer traffic via the NPC run_iptables -N WEAVE-NPC >/dev/null 2>&1 || true add_iptables_rule filter FORWARD -o $BRIDGE -j WEAVE-NPC @@ -535,41 +491,10 @@ try_create_bridge() { add_iptables_rule filter FORWARD -i $BRIDGE ! -o $BRIDGE -j ACCEPT # and allow replies back add_iptables_rule filter FORWARD -o $BRIDGE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - - # create a chain for masquerading - run_iptables -t nat -N WEAVE >/dev/null 2>&1 || true - add_iptables_rule nat POSTROUTING -j WEAVE - else - if [ -n "$LAUNCHING_ROUTER" ] ; then - if [ "$BRIDGE_TYPE" = bridge -a -z "$WEAVE_NO_FASTDP" ] && - util_op check-datapath $DATAPATH 2>/dev/null ; then - cat <&2 -WEAVE_NO_FASTDP is not set, but there is already a bridge present of -the wrong type for fast datapath. Please do 'weave reset' to remove -the bridge first. -EOF - return 1 - fi - if [ "$BRIDGE_TYPE" != bridge -a -n "$WEAVE_NO_FASTDP" ] ; then - cat <&2 -WEAVE_NO_FASTDP is set, but there is already a weave fast datapath -bridge present. Please do 'weave reset' to remove the bridge first. -EOF - return 1 - fi - fi - fi - - [ "$1" = "--without-ethtool" -o -n "$AWSVPC" ] || ethtool_tx_off_$BRIDGE_TYPE $BRIDGE - - ip link set dev $BRIDGE up - - # Configure the ARP cache parameters on the bridge interface for - # the sake of 'weave expose' - configure_arp_cache $BRIDGE } create_bridge() { + validate_bridge_type if ! try_create_bridge "$@" ; then echo "Creating bridge '$BRIDGE' failed" >&2 # reset to original value so we destroy both kinds @@ -579,6 +504,28 @@ create_bridge() { fi } +validate_bridge_type() { + detect_bridge_type || return 0 + + if [ -n "$LAUNCHING_ROUTER" ] ; then + if [ "$BRIDGE_TYPE" = bridge -a -z "$WEAVE_NO_FASTDP" ] ; then + cat <&2 +WEAVE_NO_FASTDP is not set, but there is already a bridge present of +the wrong type for fast datapath. Please do 'weave reset' to remove +the bridge first. +EOF + return 1 + fi + if [ "$BRIDGE_TYPE" != bridge -a -n "$WEAVE_NO_FASTDP" ] ; then + cat <&2 +WEAVE_NO_FASTDP is set, but there is already a weave fast datapath +bridge present. Please do 'weave reset' to remove the bridge first. +EOF + return 1 + fi + fi +} + expose_ip() { ipam_cidrs allocate_no_check_alive weave:expose $CIDR_ARGS for CIDR in $ALL_CIDRS ; do @@ -614,80 +561,6 @@ create_veth() { fi } -init_fastdp() { - # GCE has the lowest underlay network MTU we're likely to encounter on - # a local network, at 1460 bytes. To get the overlay MTU from that we - # subtract 20 bytes for the outer IPv4 header, 8 bytes for the outer - # UDP header, 8 bytes for the vxlan header, and 14 bytes for the inner - # ethernet header. In addition, we subtract 34 bytes for the ESP overhead - # which is needed for the vxlan encryption. - MTU=${WEAVE_MTU:-1376} - - # create_bridge already created the datapath netdev - ip link set dev $DATAPATH mtu $MTU -} - -init_bridge_prep() { - # Observe any MTU that is already set - [ -n "$MTU" ] || MTU=${WEAVE_MTU:-65535} - - ip link add name $BRIDGE type bridge - - # Running this from 'weave --local' when weaveexec is not on the - # path will run it as a Docker container that does not have access - # to /etc/machine-id, so will not give the full range of persistent IDs - if [ -z "$WEAVEDB_DIR_PATH" ]; then - WEAVEDB_DIR_PATH="$HOST_ROOT/$(docker inspect -f '{{with index .Mounts 0}}{{.Source}}{{end}}' $DB_CONTAINER_NAME 2>/dev/null)" - fi - MAC=$(util_op unique-id "$WEAVEDB_DIR_PATH/weave" "$HOST_ROOT") - - ip link set dev $BRIDGE address $MAC - - # Attempting to set the bridge MTU to a high value directly - # fails. Bridges take the lowest MTU of their interfaces. So - # instead we create a temporary interface with the desired - # MTU, attach that to the bridge, and then remove it again. - ip link add name v${CONTAINER_IFNAME}du mtu $MTU type dummy - ip link set dev v${CONTAINER_IFNAME}du master $BRIDGE - ip link del dev v${CONTAINER_IFNAME}du -} - -init_bridge() { - init_bridge_prep - create_veth $BRIDGE_IFNAME $PCAP_IFNAME add_iface_bridge $BRIDGE_IFNAME -} - -init_bridged_fastdp() { - # Initialise the datapath as normal. NB sets MTU for use below - init_fastdp - - # Initialise the bridge using fast datapath MTU - init_bridge_prep - - # Create linking veth pair - create_veth $BRIDGE_IFNAME $DATAPATH_IFNAME configure_veth_bridged_fastdp - - # Finally, bring the datapath up - ip link set dev $DATAPATH up -} - -configure_veth_bridged_fastdp() { - add_iface_fastdp $DATAPATH_IFNAME || return 1 - add_iface_bridge $BRIDGE_IFNAME || return 1 -} - -ethtool_tx_off_fastdp() { - true -} - -ethtool_tx_off_bridge() { - ethtool -K $1 tx off >/dev/null -} - -ethtool_tx_off_bridged_fastdp() { - true -} - destroy_bridge() { # It's important that detect_bridge_type has not been called so # we have distinct values for $BRIDGE and $DATAPATH. Make best efforts @@ -1854,8 +1727,7 @@ EOF else shift 1 fi - - create_bridge --without-ethtool "$@" + create_bridge "$@" ;; attach-bridge) if detect_bridge_type ; then @@ -2062,7 +1934,7 @@ EOF [ $# -eq 2 -a "$1" = "-h" ] || usage FQDN="$2" fi - create_bridge --without-ethtool + create_bridge expose_ip util_op expose-nat $ALL_CIDRS show_addrs $ALL_CIDRS @@ -2071,7 +1943,7 @@ EOF collect_cidr_args "$@" shift $CIDR_ARG_COUNT ipam_cidrs lookup weave:expose $CIDR_ARGS - create_bridge --without-ethtool + create_bridge for CIDR in $ALL_CIDRS ; do if ip addr show dev $BRIDGE | grep -qF $CIDR ; then ip addr del dev $BRIDGE $CIDR