forked from Lekensteyn/netns
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnetns
executable file
·163 lines (146 loc) · 4.02 KB
/
netns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/bin/bash
# Create a network namespace with two interfaces.
# Copyright (C) 2015 Peter Wu <[email protected]>
#
# Helpful article:
# "Namespaces in operation, part 7: Network namespaces [LWN.net]"
# by Jake Edge, January 22, 2014. Retrieved February 14, 2015.
# https://lwn.net/Articles/580893/
print_usage() {
cat <<EOF
Usage: $0 ns-no [dry-]{start|stop}
$0 ns-no status
$0 ns-no exec [command [command args]]
The namespace number must be between 0 and 255 (inclusive)
For namespace number 4, the layout will be:
(host) veth8 (10.9.4.1)
|
[ netns: ns4 ]
|
(namespace) veth9 (10.9.4.2)
EOF
}
cmd_exec() {
echo "# $*"
if [[ $action != dry-* ]]; then
"$@"
fi
}
rollback_cmds=()
_run_rollbacks() {
local cmd
[ ${#rollback_cmds[@]} -gt 0 ] || return
# Run all "undo" commands if any.
for cmd in "${rollback_cmds[@]}"; do
eval cmd_exec "$cmd" || :
done
rollback_cmds=()
}
D() {
local cmd="$(printf '%q ' "$@")"
# Record all "undo" commands.
if [ ${#rollback_cmds[@]} -gt 0 ]; then
rollback_cmds=( "$cmd" "${rollback_cmds[@]}" )
else
rollback_cmds=( "$cmd" )
fi
}
load_vars() {
# Always choose an even interface number here (starting at 0)
if_no=$((2*$ns_no))
ns="netns$ns_no"
ns_file=/var/run/netns/$ns
if_host="veth$((if_no))"
if_peer="veth$((if_no+1))"
addr_host="10.9.$((ns_no)).1/24"
addr_peer="10.9.$((ns_no)).2/24"
}
# A() and finish() must be defined before calling ns_cmds
ns_cmds() {
load_vars
# Create netns
A ip netns add $ns
D ip netns del $ns
# Enable loopback in netns
#ip netns exec $ns ip link set dev lo up
# Create veth pair
A ip link add $if_host type veth peer name $if_peer
D ip link del $if_host
A ip link set $if_peer netns $ns
# Assign addresses and set default route
A ip link set $if_host up
A ip addr add $addr_host dev $if_host
A ip netns exec $ns \
ip link set $if_peer up
A ip netns exec $ns \
ip addr add $addr_peer dev $if_peer
A ip netns exec $ns \
ip route add default via ${addr_host%/*} dev $if_peer
# Forward traffic
A iptables -t nat -A POSTROUTING -o $if_host -j MASQUERADE
D iptables -t nat -D POSTROUTING -o $if_host -j MASQUERADE
A iptables -A FORWARD -i $if_host -j ACCEPT
D iptables -D FORWARD -i $if_host -j ACCEPT
A iptables -A FORWARD -o $if_host -j ACCEPT
D iptables -D FORWARD -o $if_host -j ACCEPT
finish
}
### MAIN ###
ns_no=$1
action=$2
shift 2
set -e -u
if ! [[ $ns_no =~ ^[0-9]{1,3}$ ]] || [ $ns_no -gt 255 ]; then
[ -z "$ns_no" ] || echo "Namespace number must be between 0 and 255"
print_usage
exit 1
fi
case $action in
start|dry-start)
trap _run_rollbacks EXIT
A() { cmd_exec "$@"; }
# Every command was successfully executed, no need to rollback.
finish() { rollback_cmds=(); trap EXIT; echo "# Done!"; }
ns_cmds
;;
stop|dry-stop)
# Ignore start commands
A() { :; }
# All undo commands have been gathered, execute them.
finish() { _run_rollbacks; echo "# Done!"; }
ns_cmds
;;
status)
load_vars
if [ ! -e $ns_file ]; then
echo "Namespace '$ns' is inactive."
exit 0
fi
ip netns pids $ns | xargs -r ps u
cmd_exec ip netns exec $ns ip link
cmd_exec ip netns exec $ns ip addr
cmd_exec ip netns exec $ns ip route
;;
exec)
load_vars
if [ ! -e $ns_file ]; then
echo "Namespace '$ns' does not exist"
echo "Run: $0 $ns_no start"
exit 1
fi
if [ -n "${SUDO_USER:-}" ]; then
# If no command is given, enter the shell
[ $# -gt 0 ] || set -- -s
# Change user back, preserving environment (except HOME)
set -- sudo -EH -u "$SUDO_USER" "$@"
fi
# Set environment variables from a separate file (if existent)
envfile=$(dirname "$0")/env.sh
[ ! -e "$envfile" ] || . "$envfile"
exec nsenter --net=$ns_file "$@"
;;
*)
print_usage
exit 1
;;
esac