bridget/bridget.sh

323 lines
9.4 KiB
Bash
Raw Normal View History

2017-12-20 18:56:40 +03:00
#!/bin/sh
2017-12-22 14:25:48 +03:00
CNI_CONFIG="${CNI_CONFIG:-/etc/cni/net.d/10-bridget.conf}"
2017-12-21 14:34:10 +03:00
2017-12-20 18:56:40 +03:00
usage() {
cat <<EOF
Available variables:
2017-12-20 19:41:35 +03:00
- BRIDGE (example: cbr0)
2017-12-20 18:56:40 +03:00
- VLAN (example: 100)
- IFACE (example: eth0)
2017-12-20 19:41:35 +03:00
- MTU (default: 1500)
2017-12-22 14:25:48 +03:00
- CHECK_SLAVES (example: 1)
2017-12-21 03:45:27 +03:00
- POD_NETWORK (default: 10.244.0.0/16)
- DIVISION_PREFIX (default: 24)"
2017-12-22 23:37:14 +03:00
- ARP_PACKETS (default: 4)
2017-12-22 14:25:48 +03:00
- DEBUG (example: 1)
2017-12-20 18:56:40 +03:00
Short workflow:
* If bridge exists it will be used, if not exist it will be created
* If VLAN and IFACE is set, the next chain will be created:
IFACE <-- VLAN <-- BRIDGE
2017-12-22 01:25:42 +03:00
* If bridge have no IP-address it will be retrived automatically
2017-12-20 18:56:40 +03:00
This IP-address will be used as default gateway for containers
for make possible kubernetes-services.
EOF
}
error() {
2017-12-22 01:06:22 +03:00
>&2 echo -en "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:\t"
2017-12-22 00:56:24 +03:00
>&2 echo "$1"
2017-12-20 18:56:40 +03:00
>&2 usage
exit 1
}
2017-12-22 00:25:17 +03:00
log() {
2017-12-22 01:06:22 +03:00
echo -en "[$(date '+%Y-%m-%d %H:%M:%S')] INFO:\t"
2017-12-22 00:56:24 +03:00
echo "$1"
2017-12-22 00:25:17 +03:00
}
debug() {
2017-12-22 00:56:24 +03:00
if [ "$DEBUG" == 1 ]; then
2018-01-26 23:58:50 +03:00
>&2 echo -en "[$(date '+%Y-%m-%d %H:%M:%S')] DEBUG:\t"
>&2 echo "$1"
2017-12-22 00:56:24 +03:00
fi
2017-12-22 00:25:17 +03:00
}
2017-12-21 03:45:27 +03:00
next_ip() {
local IP_HEX=$(printf '%.2X%.2X%.2X%.2X\n' `echo $1 | sed -e 's/\./ /g'`)
local NEXT_IP_HEX=$(printf %.8X `echo $(( 0x$IP_HEX + 1 ))`)
local NEXT_IP=$(printf '%d.%d.%d.%d\n' `echo $NEXT_IP_HEX | sed -r 's/(..)/0x\1 /g'`)
echo $NEXT_IP
}
prev_ip() {
local IP_HEX=$(printf '%.2X%.2X%.2X%.2X\n' `echo $1 | sed -e 's/\./ /g'`)
local PREV_IP_HEX=$(printf %.8X `echo $(( 0x$IP_HEX - 1 ))`)
local PREV_IP=$(printf '%d.%d.%d.%d\n' `echo $PREV_IP_HEX | sed -r 's/(..)/0x\1 /g'`)
echo $PREV_IP
}
random_gateway() {
local IFS=
local NETWORKS_NUM="$(echo "$NETWORKS_LIST" | wc -l)"
local RANDOM_NETWORK_NUM="$(shuf -i "1-$NETWORKS_NUM" -n 1)"
local RANDOM_NETWORK="$(echo "$NETWORKS_LIST" | head -n "$RANDOM_NETWORK_NUM" | tail -n 1)"
2017-12-21 18:31:00 +03:00
unset IFS
2017-12-21 03:45:27 +03:00
local RANDOM_GATEWAY="$(next_ip $RANDOM_NETWORK)"
echo "$RANDOM_GATEWAY"
}
2017-12-22 23:37:14 +03:00
address_is_free(){
set +m
ARP_PACKETS=${ARP_PACKETS:-4}
2018-01-27 00:54:20 +03:00
# Start recording packets
if [ "$DEBUG" == 1 ]; then
2018-01-27 01:14:43 +03:00
tcpdump -nn -i "$BRIDGE" arp host "$1" 1>&2 2>/tmp/tcpdump.out &
2018-01-27 00:54:20 +03:00
else
2018-01-27 01:14:43 +03:00
tcpdump -nn -i "$BRIDGE" arp host "$1" 1>/dev/null 2>/tmp/tcpdump.out &
2018-01-27 00:54:20 +03:00
fi
2017-12-22 23:37:14 +03:00
# Wait for tcpdump
2018-01-27 01:24:12 +03:00
until grep -q 'listening on' /tmp/tcpdump.out; do sleep 1; done
2017-12-22 23:37:14 +03:00
# Start arping
local ARPING_CHECK="$(arping -fD -I "$BRIDGE" -s 0.0.0.0 -c 4 "$1" | awk '$1=="Sent" {printf $2 " "} $1=="Received" {print $2}')"
# Kill tcpdump
kill "$!" && wait "$!"
2018-01-27 01:35:09 +03:00
local TCPDUMP_COUNT="$(cat /tmp/tcpdump.out | grep -m1 "packets captured$" | awk '{print $1}'; rm -f /tmp/tcpdump.out)"
2017-12-22 23:37:14 +03:00
local ARPING_COUNT="$(echo "$ARPING_CHECK" | awk '{print $1+$2}')"
local ARPING_SEND="$(echo "$ARPING_CHECK" | awk '{print $1}')"
local ARPING_RECEIVED="$(echo "$ARPING_CHECK" | awk '{print $2}')"
2018-01-26 23:58:50 +03:00
debug "TCPDUMP_COUNT=$TCPDUMP_COUNT"
debug "ARPING_COUNT=$ARPING_COUNT"
debug "ARPING_SEND=$ARPING_SEND"
debug "ARPING_RECEIVED=$ARPING_RECEIVED"
2017-12-22 23:37:14 +03:00
if [ "$ARPING_RECEIVED" == "0" ] && [ "$TCPDUMP_COUNT" == "$ARPING_COUNT" ]; then
2018-01-26 23:58:50 +03:00
debug "[ ARPING_RECEIVED == 0 ] && [ TCPDUMP_COUNT == ARPING_COUNT ]"
2017-12-22 23:37:14 +03:00
return 0
else
2018-01-27 01:24:12 +03:00
debug "[ ARPING_RECEIVED != 0 ] || [ TCPDUMP_COUNT != ARPING_COUNT ]"
2017-12-22 23:37:14 +03:00
return 1
fi
}
gateway_is_right() {
2017-12-21 18:47:56 +03:00
(IFS= echo "$NETWORKS_LIST") | grep -q "$(prev_ip $1)"
2017-12-21 03:45:27 +03:00
}
2017-12-20 18:56:40 +03:00
# ------------------------------------------------------------------------------------
# Configure bridge
# ------------------------------------------------------------------------------------
2017-12-22 00:25:17 +03:00
log "Starting bridge configuration"
2017-12-20 18:56:40 +03:00
[ -z "$BRIDGE" ] && error "BRIDGE variable is not defined"
# Check if bridge interface exist
if ! ip link show "$BRIDGE" &> /dev/null; then
2017-12-22 00:25:17 +03:00
log "Adding new bridge $BRIDGE"
2017-12-20 18:56:40 +03:00
ip link add dev "$BRIDGE" type bridge
2017-12-22 14:38:09 +03:00
export CHECK_SLAVES=1
2017-12-22 00:25:17 +03:00
else
log "Bridge $BRIDGE already exist, use it"
2017-12-20 18:56:40 +03:00
fi
2017-12-22 00:25:17 +03:00
log "Setting bridge $BRIDGE up"
2017-12-20 18:56:40 +03:00
ip link set "$BRIDGE" up
# ------------------------------------------------------------------------------------
# Configure vlan
# ------------------------------------------------------------------------------------
2017-12-22 00:25:17 +03:00
2017-12-22 14:38:09 +03:00
if ([ ! -z "$VLAN" ] || [ ! -z "$IFACE" ]) && [ "$CHECK_SLAVES" == 1 ]; then
2017-12-22 00:25:17 +03:00
log "Starting VLAN configuration"
2017-12-20 18:56:40 +03:00
[ -z "$IFACE" ] && error "IFACE variable is not defined"
2017-12-22 04:34:52 +03:00
if [ ! -z "$VLAN" ]; then
# check if vlan interface exist
if ip link show "$IFACE.$VLAN" &> /dev/null; then
log "VLAN interface $IFACE.$VLAN already exist"
else
log "Adding new VLAN interface $IFACE.$VLAN"
ip link add link "$IFACE" name "$IFACE.$VLAN" type vlan id "$VLAN"
fi
log "Setting vlan $IFACE.$VLAN up"
ip link set dev "$IFACE.$VLAN" up
fi
fi
2017-12-22 00:25:17 +03:00
2017-12-22 04:34:52 +03:00
# ------------------------------------------------------------------------------------
# Configure slaves
# ------------------------------------------------------------------------------------
2017-12-22 00:25:17 +03:00
2017-12-22 14:38:09 +03:00
if ([ ! -z "$VLAN" ] || [ ! -z "$IFACE" ]) && [ "$CHECK_SLAVES" == 1 ]; then
2017-12-22 00:25:17 +03:00
2017-12-22 04:34:52 +03:00
log "Starting configuring slave interfaces"
2017-12-22 00:25:17 +03:00
2017-12-22 04:34:52 +03:00
if [ ! -z "$VLAN" ]; then
SLAVEIF="$IFACE.$VLAN"
2017-12-22 15:51:32 +03:00
else
2017-12-22 04:34:52 +03:00
SLAVEIF="$IFACE"
2017-12-20 18:56:40 +03:00
fi
2017-12-22 00:25:17 +03:00
2017-12-22 15:28:12 +03:00
if ! ip link show "$SLAVEIF" &> /dev/null; then
error "$SLAVEIF does not exist"
fi
2017-12-22 04:34:52 +03:00
# check if slave interface contains right master
2017-12-22 15:28:12 +03:00
MASTERIF="$(ip -o link show "$SLAVEIF" | grep -o -m1 'master [^ ]\+' | cut -d' ' -f2 )"
2017-12-22 04:34:52 +03:00
case "$MASTERIF" in
"$BRIDGE" ) log "$SLAVEIF already member of $BRIDGE" ;;
"" ) log "Adding $SLAVEIF as member to $BRIDGE"
2017-12-22 15:28:12 +03:00
ip link set "$SLAVEIF" master "$BRIDGE" ;;
2017-12-22 04:34:52 +03:00
* ) error "interface $SLAVEIF have another master" ;;
esac
2017-12-20 18:56:40 +03:00
fi
2017-12-21 03:45:27 +03:00
# ------------------------------------------------------------------------------------
# Retrive network parameters
# ------------------------------------------------------------------------------------
2017-12-22 00:25:17 +03:00
log "Starting retriving parameters"
2017-12-21 03:45:27 +03:00
POD_NETWORK="${POD_NETWORK:-10.244.0.0/16}"
DIVISION_PREFIX="${DIVISION_PREFIX:-24}"
2017-12-22 00:25:17 +03:00
log "POD_NETWORK=$POD_NETWORK"
log "DIVISION_PREFIX=$DIVISION_PREFIX"
2017-12-22 00:43:49 +03:00
set -e
2017-12-21 03:45:27 +03:00
export "POD_$(ipcalc -p "$POD_NETWORK")" # POD_PREFIX
export "POD_$(ipcalc -b "$POD_NETWORK")" # POD_BROADCAST
export "POD_$(ipcalc -n "$POD_NETWORK")" # POD_NETWORK
export "FIRST_$(ipcalc -n "$POD_NETWORK/$DIVISION_PREFIX" )" # FIRST_NETWORK
export "LAST_$(ipcalc -n "$POD_BROADCAST/$DIVISION_PREFIX" )" # LAST_NETWORK
2017-12-22 00:43:49 +03:00
set +e
2017-12-22 00:25:17 +03:00
debug "POD_PREFIX=$POD_PREFIX"
debug "POD_BROADCAST=$POD_BROADCAST"
debug "POD_NETWORK=$POD_NETWORK"
debug "FIRST_NETWORK=$FIRST_NETWORK"
debug "LAST_NETWORK=$LAST_NETWORK"
2017-12-21 03:45:27 +03:00
NETWORKS_LIST="$(
CUR_NETWORK="$LAST_NETWORK"
until [ "$CUR_NETWORK" == "$FIRST_NETWORK" ]; do
echo "$CUR_NETWORK"
export CUR_"$(ipcalc -n "$(prev_ip "$CUR_NETWORK")/$DIVISION_PREFIX")"
done
)"
# ------------------------------------------------------------------------------------
# Configure IP-address
# ------------------------------------------------------------------------------------
2017-12-22 00:25:17 +03:00
log "Starting configuring IP-address"
2017-12-21 03:45:27 +03:00
# Check ip address
2017-12-22 00:40:27 +03:00
IPADDR="$(ip -f inet -o addr show "$BRIDGE" | grep -o -m1 'inet [^ /]*' | cut -d' ' -f2)"
2017-12-21 03:45:27 +03:00
# If ip not exist
if [ -z "$IPADDR" ]; then
2017-12-22 00:25:17 +03:00
2018-01-26 23:58:50 +03:00
if [ -f "$CNI_CONFIG" ]; then
CHECKING_IP=$(sed -n 's/.*"gateway": "\(.*\)",/\1/p' "$CNI_CONFIG")
log "Cni config found, taking old address $CHECKING_IP"
rm -f "$CNI_CONFIG"
fi
if [ -z $CHECKING_IP ] || ! gateway_is_right "$CHECKING_IP"; then
CHECKING_IP="$(random_gateway)"
log "New address generated $CHECKING_IP"
fi
log "Checking $CHECKING_IP"
while ! address_is_free "$CHECKING_IP"; do
log "Address $CHECKING_IP is not free"
CHECKING_IP="$(random_gateway)"
log "Taking another one $CHECKING_IP"
done
log "Address $CHECKING_IP is free, using it as gateway"
IPADDR="$CHECKING_IP"
2017-12-22 00:25:17 +03:00
log "Configuring $IPADDR/$POD_PREFIX on $BRIDGE"
2017-12-21 15:45:30 +03:00
ip addr change "$IPADDR/$POD_PREFIX" dev "$BRIDGE"
2017-12-22 00:25:17 +03:00
2017-12-21 03:45:27 +03:00
else
2017-12-22 00:25:17 +03:00
2017-12-22 23:37:14 +03:00
if ! gateway_is_right "$IPADDR"; then
2017-12-21 03:45:27 +03:00
error "$BRIDGE already have IP address not from the list"
fi
2017-12-22 01:01:57 +03:00
log "IP-address $IPADDR already set, use it"
2017-12-22 00:25:17 +03:00
2017-12-21 03:45:27 +03:00
fi
2017-12-20 18:56:40 +03:00
# ------------------------------------------------------------------------------------
# Configure cni
# ------------------------------------------------------------------------------------
2017-12-21 03:45:27 +03:00
2017-12-22 00:25:17 +03:00
log "Starting generating CNI configuration"
2017-12-22 00:43:49 +03:00
set -e
2017-12-21 03:45:27 +03:00
GATEWAY="$IPADDR"
SUBNET="${POD_NETWORK}/${POD_PREFIX}"
FIRST_IP="$(next_ip "${GATEWAY}")"
LAST_IP="$(prev_ip "$(ipcalc -b "${GATEWAY}/${DIVISION_PREFIX}" | cut -d= -f2)")"
2017-12-22 00:43:49 +03:00
set +e
2017-12-22 00:25:17 +03:00
debug "GATEWAY=$GATEWAY"
debug "SUBNET=$SUBNET"
debug "FIRST_IP=$FIRST_IP"
debug "LAST_IP=$LAST_IP"
log "Writing $CNI_CONFIG"
2017-12-21 14:34:10 +03:00
cat > $CNI_CONFIG <<EOT
2017-12-20 18:56:40 +03:00
{
2017-12-22 14:25:48 +03:00
"name": "bridget",
2017-12-20 18:56:40 +03:00
"type": "bridge",
"bridge": "${BRIDGE}",
2017-12-21 20:45:21 +03:00
"ipMasq": true,
2017-12-20 19:39:05 +03:00
"mtu": ${MTU:-1500},
2017-12-20 18:56:40 +03:00
"ipam": {
2017-12-21 03:45:27 +03:00
"type": "host-local",
"subnet": "${SUBNET}",
"rangeStart": "${FIRST_IP}",
"rangeEnd": "${LAST_IP}",
2017-12-21 14:34:10 +03:00
"gateway": "${GATEWAY}",
2017-12-21 03:45:27 +03:00
"routes": [
{ "dst": "0.0.0.0/0" }
]
2017-12-20 18:56:40 +03:00
}
}
EOT
2017-12-22 00:25:17 +03:00
debug "$(cat "$CNI_CONFIG")"
2017-12-20 18:56:40 +03:00
# ------------------------------------------------------------------------------------
2017-12-21 15:26:07 +03:00
# Sleep gently
2017-12-20 18:56:40 +03:00
# ------------------------------------------------------------------------------------
2018-01-26 23:58:50 +03:00
exec tail -f /dev/null