]> ruderich.org/simon Gitweb - linux-network-namespace-labs/linux-network-namespace-labs.git/blob - README.adoc
3c258fa0d73a5f104537121f08cab9a8759827fd
[linux-network-namespace-labs/linux-network-namespace-labs.git] / README.adoc
1 = README
2
3 linux-network-namespace-labs (lnnl) is a small program to easily create
4 networking lab setups based on Linux network namespaces. It provides a quick
5 way to set up labs using a text file describing the architecture (networks,
6 nodes, links, commands). This is much simpler than running each node in a
7 separate virtual machine or manually allocating the IP addresses for each
8 node. It is licensed under GPLv3+.
9
10
11 == Requirements
12
13 === Build
14
15 - Go, no external dependencies
16
17 === Run
18
19 - Linux compiled with `CONFIG_NET_NS` (available on most modern systems)
20 - iproute2 (`ip`)
21 - root (or unprivileged user namespaces, see below)
22
23
24 == Build
25
26     $ go build
27
28 Then copy the binary `lnnl` to a directory in your `$PATH`.
29
30
31 == Usage
32
33 The following configuration from `examples/readme/` sets up a lab with three
34 nodes (routers) and configures static routes.
35
36 ----
37 # Network range for loopback addresses of the nodes
38 net loops 192.0.2.0/24 3fff::/20
39 # Network range for interfaces between nodes
40 net addrs 198.51.100.0/24 2001:db8::/32
41
42 # Set up three nodes (routers) and assign IPv4 and IPv6 loopback addresses
43 node r1 loops
44 node r2 loops
45 node r3 loops
46
47 # Links between routers: /31 or /127 prefixes are used for each interface
48 link r1 r2 addrs
49 link r2 r3 addrs
50
51 # Commands to run on each node; $1 is the node name (= name of the network
52 # namespace). Here it's used to set up static routes but can also be used to
53 # start routing daemons like Bird.
54 cmd ./setup.sh $1
55 ----
56
57 Then set up the lab by running (as root):
58
59     # cd examples/readme
60     # lnnl up lab.conf
61     [...]
62
63 Now you can enter the network namespace of each router and test a simple
64 traceroute:
65
66     # ip netns exec r1 sh
67     # ip -br a
68     lo               UNKNOWN        127.0.0.1/8 ::1/128
69     lo2              UNKNOWN        192.0.2.0/32 3fff::/128 fe80::438:67ff:fe0a:4e58/64
70     r2@if287         UP             198.51.100.0/31 2001:db8::/127 fe80::a896:cdff:fe58:5c23/64
71     # traceroute 192.0.2.2
72     traceroute to 192.0.2.2 (192.0.2.2), 30 hops max, 60 byte packets
73      1  r2 (198.51.100.1)  0.937 ms  0.818 ms  0.768 ms
74      2  r3-loop (192.0.2.2)  0.722 ms  0.650 ms  0.603 ms
75
76 Use `exit` to leave the network namespace.
77
78 The `/etc/hosts` file of each node (via `/etc/netns/<ns>/hosts`) is
79 automatically filled with all known addresses so you can use hostnames as
80 well:
81
82     # ping -c1 r3-loop
83     PING r3-loop(r3-loop (3fff::2)) 56 data bytes
84     64 bytes from r3-loop (3fff::2): icmp_seq=1 ttl=63 time=0.266 ms
85     --- r3-loop ping statistics ---
86     1 packets transmitted, 1 received, 0% packet loss, time 0ms
87     rtt min/avg/max/mdev = 0.266/0.266/0.266/0.000 ms
88
89 When you change the configuration you can simply rerun "up" and it will remove
90 the lab (and kill all processes inside it) before restarting it:
91
92     # lnnl up lab.conf
93     [...]
94
95 When you're done you can remove the lab with:
96
97     # lnnl down lab.conf
98     [...]
99
100 To get an overview of the network you can create a
101 https://en.wikipedia.org/wiki/DOT_(graph_description_language)[DOT] file:
102
103     $ lnnl dot lab.conf lab.dot
104     $ dot -Tpng lab.dot > lab.png
105
106 image::examples/readme/lab.png[DOT style diagram of network nodes and links]
107
108
109 === Running without root using unprivileged user namespaces
110
111 Creating a named network namespace within a user namespace requires a few
112 extra steps. Use the following commands:
113
114     $ unshare --user --net --mount --map-auto --map-root-user
115     # mount -t tmpfs tmpfs /run
116     # mount -t tmpfs tmpfs /etc/netns
117     # export PATH=$PATH:/usr/sbin
118
119 The tmpfs mounts make the directories writable within the user namespace. The
120 PATH is updated to ensure `sysctl` is found.
121
122 To run the bird-ospf example:
123
124     # mkdir /run/bird
125     # lnnl up examples/bird-ospf/lab.conf
126     [...]
127     # ip netns exec r1 ip -br a
128     [...]
129     # birdc -s /run/bird/r1.ctl
130     [...]
131
132 To enter the namespace from another terminal (get the PID with `echo $$`):
133
134     $ nsenter --user --net --mount --target $pid
135
136
137 == Examples
138
139 Have a look at `examples/`, which also includes running
140 https://bird.network.cz/[Bird] on each node and spawning a Podman container
141 inside the created nodes with https://frrouting.org/[FRR].
142
143
144 == Syntax of configuration file
145
146 One option per line, empty lines are permitted as well as comments starting
147 with `#`.
148
149 The config file is parsed from top to bottom and the options "net", "node",
150 "link" must be given in this order. "cmd" can be put anywhere (but is only
151 executed at the end).
152
153 === Option "net"
154
155     "net" <name> <prefix>...
156
157 "net" creates a new prefix which is used to allocate addresses for loopback
158 and link interfaces. Multiple IPv4 and IPv6 prefixes can be specified. When
159 the network is used, one address from each prefix is assigned to the
160 interface. "net"s used for loopback interfaces must be separate from "net"s
161 used for link interfaces.
162
163 === Option "node"
164
165     "node" <name> [<loopback-net-name>...]
166
167 "node" creates a new node (router) and (if specified) assigns loopback
168 addresses from the given networks. The loopback addresses are assigned to a
169 new interface "lo2".
170
171 === Option "link"
172
173     "link" <node> <node> <net-name>|"-" ["l3"]
174
175 "link" creates links between nodes. The IP addresses are taken from the given
176 network. /31 is used for IPv4- and /127 for IPv6-prefixes. If "-" is used as
177 the net-name then no addresses are assigned (useful for unnumbered links). The
178 MAC address is dynamically allocated by the kernel. The link is named after
179 the node "on the other side". Multiple links can be created between two nodes.
180 In this case, suffixes like "_2", "_3", etc. are appended to the interface
181 name. By default, veth interfaces are used. Adding "l3" changes this to
182 netkit, which provides a layer-3 connection without needing ARP (requires
183 kernel 6.7, iproute2 6.8).
184
185 === Option "cmd"
186
187     "cmd" <string-passed-to-sh-c>
188
189 "cmd" runs the given command (by passing it as is to `sh -c`) on each node.
190 The first argument is the name of the node (which is also the name of the
191 network namespace). This can be used to run setup commands or routing daemons
192 on the nodes.
193
194 If "cmd" is not flexible enough you can simply use `ip netns exec` to manually
195 run commands on specific nodes.
196
197
198 == Authors
199
200 Written by Simon Ruderich <simon@ruderich.org>.
201
202 Please report bugs, feature requests and patches via email.
203
204
205 == License
206
207 This program is licensed under GPL version 3 or later.
208
209 Copyright (C) 2024  Simon Ruderich
210
211 This program is free software: you can redistribute it and/or modify
212 it under the terms of the GNU General Public License as published by
213 the Free Software Foundation, either version 3 of the License, or
214 (at your option) any later version.
215
216 This program is distributed in the hope that it will be useful,
217 but WITHOUT ANY WARRANTY; without even the implied warranty of
218 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
219 GNU General Public License for more details.
220
221 You should have received a copy of the GNU General Public License
222 along with this program.  If not, see <https://www.gnu.org/licenses/>.