路由原理
#!/bin/sh# Author: fasion# Created time: 2020-10-11 15:39:21# Last Modified by: fasion# Last Modified time: 2020-12-23 18:51:23NS_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