路由原理

    1. #!/bin/sh
    2. # Author: fasion
    3. # Created time: 2020-10-11 15:39:21
    4. # Last Modified by: fasion
    5. # Last Modified time: 2020-12-23 18:51:23
    6. NS_ROOT='/var/run'
    7. NS_ROOT='/data/run'
    8. NETNS_ROOT="$NS_ROOT/netns"
    9. UTSNS_ROOT="$NS_ROOT/utsns"
    10. MNTNS_ROOT="$NS_ROOT/mntns"
    11. # MNTNS_ROOT="/data/mntns"
    12. NSFS_ROOT='/data/nsfs'
    13. err_exit() {
    14. retcode="$1"
    15. shift
    16. echo "$@"
    17. exit "$retcode"
    18. }
    19. err_return() {
    20. retcode="$1"
    21. shift
    22. echo "$@"
    23. return "$retcode"
    24. }
    25. create-hub() {
    26. local name="$1"
    27. ip link add "$name" type bridge ageing_time 0 &&
    28. ip link set "$name" up ||
    29. err_return 1 "cat not create hub $name"
    30. }
    31. # 创建一个交换机(网桥)
    32. create-switch() {
    33. local name="$1"
    34. ip link add "$name" type bridge &&
    35. ip link set "$name" up ||
    36. err_return 1 "cat not create switch $name"
    37. }
    38. create-netns-for-nsvm() {
    39. local vm_name="$1"
    40. mkdir -p "$NETNS_ROOT" &&
    41. touch "$NETNS_ROOT/$vm_name" &&
    42. unshare --net="$NETNS_ROOT/$vm_name" true ||
    43. err_return 1 "cat not create netns for vm $vm_name"
    44. }
    45. create-utsns-for-nsvm() {
    46. local vm_name="$1"
    47. mkdir -p "$UTSNS_ROOT" &&
    48. touch "$UTSNS_ROOT/$vm_name" &&
    49. unshare --uts="$UTSNS_ROOT/$vm_name" hostname "$vm_name" ||
    50. err_return 1 "cat not create utsns for vm $vm_name"
    51. }
    52. create-mntns-for-nsvm() {
    53. local vm_name="$1"
    54. mkdir -p "$MNTNS_ROOT" &&
    55. touch "$MNTNS_ROOT/$vm_name" &&
    56. unshare --mount="$MNTNS_ROOT/$vm_name" true ||
    57. err_return 1 "cat not create utsns for vm $vm_name"
    58. }
    59. create-rootfs-for-nsvm() {
    60. local rootfs="/data/rootfs"
    61. if [ ! -e "$rootfs" ]; then
    62. mkdir -p "$rootfs" || exit
    63. mount -o bind,ro / "$rootfs" || exit
    64. fi
    65. local vm_name="$1"
    66. local ns_path="$NSFS_ROOT/$vm_name"
    67. local upperdir="$ns_path/upperdir"
    68. local workdir="$ns_path/workdir"
    69. local vmroot="$ns_path/rootfs"
    70. mkdir -p "$ns_path" || return
    71. mkdir -p "$upperdir" || return
    72. mkdir -p "$workdir" || return
    73. mkdir -p "$vmroot" || return
    74. mkdir -p "$upperdir/etc" &&
    75. cp /etc/resolv.conf "$upperdir/etc" &&
    76. echo "$vm_name" > "$upperdir/etc/hostname" &&
    77. echo "127.0.0.1 localhost" > "$upperdir/etc/hosts" || return
    78. mount -t overlay -o "lowerdir="$rootfs",upperdir=$upperdir,workdir=$workdir" overlay "$vmroot" || return
    79. }
    80. mount-rootfs-for-nsvm() {
    81. local vm_name="$1"
    82. local ns_path="$NSFS_ROOT/$vm_name"
    83. local vmroot="$ns_path/rootfs"
    84. exec-in-nsvm "$vm_name" mount --bind "$vmroot" / || return
    85. exec-in-nsvm "$vm_name" mount -t proc proc /proc || return
    86. exec-in-nsvm "$vm_name" mount -t sysfs sysfs /sys || return
    87. }
    88. # 创建namespace
    89. # 分别是net/UTS/rootfs/mount/挂载
    90. create-nsvm() {
    91. local vm_name="$1"
    92. create-netns-for-nsvm "$vm_name" || return 1
    93. create-utsns-for-nsvm "$vm_name" || return 1
    94. create-rootfs-for-nsvm "$vm_name" || return 1
    95. create-mntns-for-nsvm "$vm_name" || return 1
    96. mount-rootfs-for-nsvm "$vm_name" || return 1
    97. }
    98. init-nsvm() {
    99. local vm_name="$1"
    100. nsenter --net="$NETNS_ROOT/$vm_name" ip addr add 127.0.0.1/8 dev lo &&
    101. nsenter --net="$NETNS_ROOT/$vm_name" ip link set lo up ||
    102. err_return 1 "cat not bring lo up for vm $vm_name"
    103. while [ -n "$2" ]; do
    104. nsenter --net="$NETNS_ROOT/$vm_name" ip link set "$2" up ||
    105. err_return 1 "cat not bring $2 up for vm $vm_name"
    106. shift
    107. done
    108. }
    109. disable-ipv6-for-nsvm() {
    110. while [ -n "$1" ]; do
    111. exec-in-nsvm "$1" bash -c "echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6"
    112. shift
    113. done
    114. }
    115. exec-in-nsvm() {
    116. local name="$1"
    117. shift
    118. nsenter --uts="$UTSNS_ROOT/$name" --net="$NETNS_ROOT/$name" --mount="$MNTNS_ROOT/$name" "$@"
    119. }
    120. add-routes-for-nsvm() {
    121. groups=(${2//;/ })
    122. for group in ${groups[@]}; do
    123. # echo "group=$group"
    124. if [ -z "$group" ]; then
    125. continue
    126. fi
    127. gw=`echo "$group" | cut -d : -f 1`
    128. if [ -z "$gw" ]; then
    129. continue
    130. fi
    131. # echo "gw=$gw"
    132. routestr=`echo "$group" | cut -d : -f 2`
    133. if [ -z "$routestr" ]; then
    134. continue
    135. fi
    136. # echo "routestr=$routestr"
    137. routes=(${routestr//,/ })
    138. for route in ${routes[@]}; do
    139. # echo "route=$route"
    140. if [ -z "$route" ]; then
    141. continue
    142. fi
    143. exec-in-nsvm $1 ip route add "$route" via "$gw"
    144. done
    145. done
    146. }
    147. enter-nsvm() {
    148. local name="$1"
    149. exec-in-nsvm "$name" bash -c "cd; exec zsh"
    150. }
    151. move-iface-to-nsvm() {
    152. local iface_name="$1"
    153. local vm_name="$2"
    154. ip link set "$iface_name" netns "$NETNS_ROOT/$vm_name"
    155. }
    156. connect-two-nsvm() {
    157. local vm_name1="$1"
    158. local dev_name1="$2"
    159. local vm_name2="$3"
    160. local dev_name2="$4"
    161. local link_name="$vm_name1-$vm_name2"
    162. local peer_name="$vm_name2-$vm_name1"
    163. ip link add "$link_name" type veth peer name "$peer_name" &&
    164. ip link set "$link_name" netns "$NETNS_ROOT/$vm_name1" name "$dev_name1" &&
    165. ip link set "$peer_name" netns "$NETNS_ROOT/$vm_name2" name "$dev_name2" ||
    166. err_return 1 "can not connect vm1 $vm_name1/$dev_name1 to vm2 $vm_name2/$dev_name2"
    167. }
    168. connect-nsvm-to-bridge() {
    169. local vm_name="$1"
    170. local dev_name="$2"
    171. local bridge_name="$3"
    172. local link_name="$vm_name-$dev_name"
    173. local peer_name="$vm_name-$dev_name-p"
    174. ip link add "$link_name" type veth peer name "$peer_name" &&
    175. ip link set "$link_name" netns "$NETNS_ROOT/$vm_name" name "$dev_name" &&
    176. ip link set "$peer_name" up master "$bridge_name" ||
    177. err_return 1 "cat not connect vm $vm_name to $bridge_name through $dev_name"
    178. }
    179. connect-nsvm-to-hub() {
    180. connect-nsvm-to-bridge "$@"
    181. }
    182. connect-nsvm-to-switch() {
    183. connect-nsvm-to-bridge "$@"
    184. }
    185. connect-two-bridge() {
    186. local bridge_name1="$1"
    187. local bridge_name2="$2"
    188. local link_name="$bridge_name1-$bridge_name2"
    189. local peer_name="$bridge_name2-$bridge_name1"
    190. ip link add "$link_name" type veth peer name "$peer_name" &&
    191. ip link set "$link_name" master "$bridge_name1" up &&
    192. ip link set "$peer_name" master "$bridge_name2" up ||
    193. err_return 1 "cat not connect bridge1 $bridge_name1 to bridge2 $bridge_name2"
    194. }
    195. # 创建一个网络节点,一台机器
    196. create-node() {
    197. name="$1"
    198. # 创建namespace?
    199. create-nsvm "$name" || exit
    200. # 初始化namespace?
    201. init-nsvm "$name" || exit
    202. }
    203. network-switch-name() {
    204. echo "$1-switch"
    205. }
    206. create-network() {
    207. name="$1"
    208. switch_name=`network-switch-name "$name"`
    209. create-switch "$switch_name" || exit
    210. }
    211. connect-node-to-network() {
    212. node="$1"
    213. network="$2"
    214. iface="$3"
    215. mac="$4"
    216. ip="$5"
    217. switch=`network-switch-name "$network"`
    218. connect-nsvm-to-switch "$node" "$iface" "$switch" || exit
    219. exec-in-nsvm "$node" ip link set "$iface" up || exit
    220. if [ -n "$mac" ]; then
    221. exec-in-nsvm "$node" ip link set dev "$iface" address "$mac" || exit
    222. fi
    223. if [ -n "$ip" ]; then
    224. exec-in-nsvm "$node" ip addr add "$ip" dev "$iface" || exit
    225. fi
    226. }
    227. default-iface() {
    228. ip route | grep default | awk '{print $5}'
    229. }
    230. iface-ip() {
    231. ip addr show "$1" |grep inet | awk '{print $2}' | cut -f 1 -d /
    232. }
    233. setup-snat-for-default-iface() {
    234. iface=`default-iface`
    235. [ -n "$iface" ] || return
    236. ip=`iface-ip "$iface"`
    237. [ -n "$ip" ] || return
    238. iptables -t nat -A POSTROUTING -o "$iface" -j MASQUERADE
    239. #iptables -t nat -A POSTROUTING -o "$iface" -s 192.168.0.0/16 -j SNAT --to "$ip" || return
    240. }
    241. if [ -n "$1" ]; then
    242. "$@"
    243. fi