路由原理
#!/bin/sh
# Author: fasion
# Created time: 2020-10-11 15:39:21
# Last Modified by: fasion
# Last Modified time: 2020-12-23 18:51:23
NS_ROOT='/var/run'
NS_ROOT='/data/run'
NETNS_ROOT="$NS_ROOT/netns"
UTSNS_ROOT="$NS_ROOT/utsns"
MNTNS_ROOT="$NS_ROOT/mntns"
# MNTNS_ROOT="/data/mntns"
NSFS_ROOT='/data/nsfs'
err_exit() {
retcode="$1"
shift
echo "$@"
exit "$retcode"
}
err_return() {
retcode="$1"
shift
echo "$@"
return "$retcode"
}
create-hub() {
local name="$1"
ip link add "$name" type bridge ageing_time 0 &&
ip link set "$name" up ||
err_return 1 "cat not create hub $name"
}
# 创建一个交换机(网桥)
create-switch() {
local name="$1"
ip link add "$name" type bridge &&
ip link set "$name" up ||
err_return 1 "cat not create switch $name"
}
create-netns-for-nsvm() {
local vm_name="$1"
mkdir -p "$NETNS_ROOT" &&
touch "$NETNS_ROOT/$vm_name" &&
unshare --net="$NETNS_ROOT/$vm_name" true ||
err_return 1 "cat not create netns for vm $vm_name"
}
create-utsns-for-nsvm() {
local vm_name="$1"
mkdir -p "$UTSNS_ROOT" &&
touch "$UTSNS_ROOT/$vm_name" &&
unshare --uts="$UTSNS_ROOT/$vm_name" hostname "$vm_name" ||
err_return 1 "cat not create utsns for vm $vm_name"
}
create-mntns-for-nsvm() {
local vm_name="$1"
mkdir -p "$MNTNS_ROOT" &&
touch "$MNTNS_ROOT/$vm_name" &&
unshare --mount="$MNTNS_ROOT/$vm_name" true ||
err_return 1 "cat not create utsns for vm $vm_name"
}
create-rootfs-for-nsvm() {
local rootfs="/data/rootfs"
if [ ! -e "$rootfs" ]; then
mkdir -p "$rootfs" || exit
mount -o bind,ro / "$rootfs" || exit
fi
local vm_name="$1"
local ns_path="$NSFS_ROOT/$vm_name"
local upperdir="$ns_path/upperdir"
local workdir="$ns_path/workdir"
local vmroot="$ns_path/rootfs"
mkdir -p "$ns_path" || return
mkdir -p "$upperdir" || return
mkdir -p "$workdir" || return
mkdir -p "$vmroot" || return
mkdir -p "$upperdir/etc" &&
cp /etc/resolv.conf "$upperdir/etc" &&
echo "$vm_name" > "$upperdir/etc/hostname" &&
echo "127.0.0.1 localhost" > "$upperdir/etc/hosts" || return
mount -t overlay -o "lowerdir="$rootfs",upperdir=$upperdir,workdir=$workdir" overlay "$vmroot" || return
}
mount-rootfs-for-nsvm() {
local vm_name="$1"
local ns_path="$NSFS_ROOT/$vm_name"
local vmroot="$ns_path/rootfs"
exec-in-nsvm "$vm_name" mount --bind "$vmroot" / || return
exec-in-nsvm "$vm_name" mount -t proc proc /proc || return
exec-in-nsvm "$vm_name" mount -t sysfs sysfs /sys || return
}
# 创建namespace
# 分别是net/UTS/rootfs/mount/挂载
create-nsvm() {
local vm_name="$1"
create-netns-for-nsvm "$vm_name" || return 1
create-utsns-for-nsvm "$vm_name" || return 1
create-rootfs-for-nsvm "$vm_name" || return 1
create-mntns-for-nsvm "$vm_name" || return 1
mount-rootfs-for-nsvm "$vm_name" || return 1
}
init-nsvm() {
local vm_name="$1"
nsenter --net="$NETNS_ROOT/$vm_name" ip addr add 127.0.0.1/8 dev lo &&
nsenter --net="$NETNS_ROOT/$vm_name" ip link set lo up ||
err_return 1 "cat not bring lo up for vm $vm_name"
while [ -n "$2" ]; do
nsenter --net="$NETNS_ROOT/$vm_name" ip link set "$2" up ||
err_return 1 "cat not bring $2 up for vm $vm_name"
shift
done
}
disable-ipv6-for-nsvm() {
while [ -n "$1" ]; do
exec-in-nsvm "$1" bash -c "echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6"
shift
done
}
exec-in-nsvm() {
local name="$1"
shift
nsenter --uts="$UTSNS_ROOT/$name" --net="$NETNS_ROOT/$name" --mount="$MNTNS_ROOT/$name" "$@"
}
add-routes-for-nsvm() {
groups=(${2//;/ })
for group in ${groups[@]}; do
# echo "group=$group"
if [ -z "$group" ]; then
continue
fi
gw=`echo "$group" | cut -d : -f 1`
if [ -z "$gw" ]; then
continue
fi
# echo "gw=$gw"
routestr=`echo "$group" | cut -d : -f 2`
if [ -z "$routestr" ]; then
continue
fi
# echo "routestr=$routestr"
routes=(${routestr//,/ })
for route in ${routes[@]}; do
# echo "route=$route"
if [ -z "$route" ]; then
continue
fi
exec-in-nsvm $1 ip route add "$route" via "$gw"
done
done
}
enter-nsvm() {
local name="$1"
exec-in-nsvm "$name" bash -c "cd; exec zsh"
}
move-iface-to-nsvm() {
local iface_name="$1"
local vm_name="$2"
ip link set "$iface_name" netns "$NETNS_ROOT/$vm_name"
}
connect-two-nsvm() {
local vm_name1="$1"
local dev_name1="$2"
local vm_name2="$3"
local dev_name2="$4"
local link_name="$vm_name1-$vm_name2"
local peer_name="$vm_name2-$vm_name1"
ip link add "$link_name" type veth peer name "$peer_name" &&
ip link set "$link_name" netns "$NETNS_ROOT/$vm_name1" name "$dev_name1" &&
ip link set "$peer_name" netns "$NETNS_ROOT/$vm_name2" name "$dev_name2" ||
err_return 1 "can not connect vm1 $vm_name1/$dev_name1 to vm2 $vm_name2/$dev_name2"
}
connect-nsvm-to-bridge() {
local vm_name="$1"
local dev_name="$2"
local bridge_name="$3"
local link_name="$vm_name-$dev_name"
local peer_name="$vm_name-$dev_name-p"
ip link add "$link_name" type veth peer name "$peer_name" &&
ip link set "$link_name" netns "$NETNS_ROOT/$vm_name" name "$dev_name" &&
ip link set "$peer_name" up master "$bridge_name" ||
err_return 1 "cat not connect vm $vm_name to $bridge_name through $dev_name"
}
connect-nsvm-to-hub() {
connect-nsvm-to-bridge "$@"
}
connect-nsvm-to-switch() {
connect-nsvm-to-bridge "$@"
}
connect-two-bridge() {
local bridge_name1="$1"
local bridge_name2="$2"
local link_name="$bridge_name1-$bridge_name2"
local peer_name="$bridge_name2-$bridge_name1"
ip link add "$link_name" type veth peer name "$peer_name" &&
ip link set "$link_name" master "$bridge_name1" up &&
ip link set "$peer_name" master "$bridge_name2" up ||
err_return 1 "cat not connect bridge1 $bridge_name1 to bridge2 $bridge_name2"
}
# 创建一个网络节点,一台机器
create-node() {
name="$1"
# 创建namespace?
create-nsvm "$name" || exit
# 初始化namespace?
init-nsvm "$name" || exit
}
network-switch-name() {
echo "$1-switch"
}
create-network() {
name="$1"
switch_name=`network-switch-name "$name"`
create-switch "$switch_name" || exit
}
connect-node-to-network() {
node="$1"
network="$2"
iface="$3"
mac="$4"
ip="$5"
switch=`network-switch-name "$network"`
connect-nsvm-to-switch "$node" "$iface" "$switch" || exit
exec-in-nsvm "$node" ip link set "$iface" up || exit
if [ -n "$mac" ]; then
exec-in-nsvm "$node" ip link set dev "$iface" address "$mac" || exit
fi
if [ -n "$ip" ]; then
exec-in-nsvm "$node" ip addr add "$ip" dev "$iface" || exit
fi
}
default-iface() {
ip route | grep default | awk '{print $5}'
}
iface-ip() {
ip addr show "$1" |grep inet | awk '{print $2}' | cut -f 1 -d /
}
setup-snat-for-default-iface() {
iface=`default-iface`
[ -n "$iface" ] || return
ip=`iface-ip "$iface"`
[ -n "$ip" ] || return
iptables -t nat -A POSTROUTING -o "$iface" -j MASQUERADE
#iptables -t nat -A POSTROUTING -o "$iface" -s 192.168.0.0/16 -j SNAT --to "$ip" || return
}
if [ -n "$1" ]; then
"$@"
fi