Mininet creates a realistic virtual network, running real kernel, switch and application code, on a single machine (VM, cloud or native)
-- mininet.org
A little detour:
func main() {
err := syscall.Unshare(syscall.CLONE_NEWNS);
}
static int child(void *arg) {
struct utsname uts;
sethostname(arg, "ernie")
uname(&uts)
printf("nodename in child: %s\n", uts.nodename);
return 0;
}
int main() {
struct utsname uts;
/* Allocate stack for child */
char *stack = malloc(STACK_SIZE);
if (stack == NULL)
return -1;
/* Start new kernel task in new UTS namespace */
pid_t child_pid = clone(child, stack + STACK_SIZE, CLONE_NEWUTS | SIGCHLD, NULL);
/* Output hostname */
uname(&uts)
printf("nodename in parent: %s\n", uts.nodename);
}
fd := syscall.Open("/proc/1234/ns/uts", syscall.O_RDONLY);
err := unix.Setns(fd, syscall.CLONE_NEWUTS);
Note: Can only set a single namespace per netns(2)
invocation.
pid_t pid = 1234;
int fd = pidfd_open(pid, 0);
setns(fd, CLONE_NEWUTS | CLONE_NEWNET);
Note: Can only set a multiple namespaces per netns(2)
invocation.
err := syscall.Mount("/proc/self/ns/uts",
"/home/acs/my_uts_namespace", "", syscall.MS_BIND, nil);
fd := syscall.Open("/home/acs/my_uts_namespace", syscall.O_RDONLY);
err := unix.Setns(fd, syscall.CLONE_NEWUTS);
veth
network interfaces which are associated to separate nodes/etc/hosts
files between networks
n, _ := g.NewNetwork("mynet")
h1, _ := n.AddHost("h1")
h2, _ := n.AddHost("h2")
n.AddLink(
o.Interface("eth0", h1, o.AddressIPv4(10, 0, 0, 1, 24)),
o.Interface("eth0", h2, o.AddressIPv4(10, 0, 0, 2, 24)),
)
h1.Ping(h2)
// Run a simple process synchronously
h1.Run("ping", "h2")
// And asynchronously
_, _, e, _ := h1.Start("ping", "h2")
time.Sleep(5 * time.Second)
e.Process.Kill()
e.Wait()
// Call a function inside a network namespace
h1.RunFunc(func() {
r := http.Get("http://h2:8080")
io.Copy(os.Stdout, r.Body)
})
sw, _ := n.AddSwitch("sw")
h1, _ := n.AddHost("h1", o.Interface("eth0", sw,
o.AddressIPv4(10, 0, 0, 1, 24)))
h2, _ := n.AddHost("h2", o.Interface("eth0", sw,
o.AddressIPv4(10, 0, 0, 2, 24)))
h1.Ping(h2)
sw1, _ := n.AddSwitch("sw1")
sw2, _ := n.AddSwitch("sw2")
h1, _ := n.AddHost("h1", o.Interface("eth0", sw1,
o.AddressIPv4(10, 0, 0, 2, 24)))
h2, _ := n.AddHost("h2", o.Interface("eth0", sw2,
o.AddressIPv4(10, 0, 1, 2, 24)))
n.AddRouter("r1",
o.Interface("eth0", sw, o.AddressIPv4(10, 0, 0, 1, 24)),
o.Interface("eth1", sw, o.AddressIPv4(10, 0, 1, 1, 24))
)
h1.Ping(h2)
sw1, _ := n.AddSwitch("sw1")
sw2, _ := n.AddSwitch("sw2")
h1, _ := n.AddHost("h1", o.Interface("eth0", sw1,
o.AddressIPv4(10, 0, 0, 2, 24)))
h2, _ := n.AddHost("h2", o.Interface("eth0", sw2,
o.AddressIPv4(10, 0, 1, 2, 24)))
n.AddNAT("n1",
o.Interface("eth0", sw, o.SouthBound,
o.AddressIPv4(10, 0, 0, 1, 24)),
o.Interface("eth1", sw, o.NorthBound,
o.AddressIPv4(10, 0, 1, 1, 24))
)
h1.Ping(h2)
var firstSwitch *g.Switch = n.AddSwitch("sw0")
var lastSwitch *g.Switch = nil
for i := 1; i < 100; i++ {
swName := fmt.Printf("sw%d", i)
rtrName := fmt.Printf("r%d", i)
newSwitch, _ := n.AddSwitch(swName)
n.AddRouter(rtrName,
o.Interface("eth0", lastSwitch,
o.AddressIPv4(10, 0, 0, 1, 24)),
o.Interface("eth1", newSwitch,
o.AddressIPv4(10, 0, 1, 1, 24))
)
lastSwitch = newSwitch
}
h1, _ := n.AddHost("h1", o.Interface("eth0", firstSwitch,
o.AddressIPv4(10, 0, 0, 2, 24)))
h2, _ := n.AddHost("h2", o.Interface("eth0", lastSwitch,
o.AddressIPv4(10, 0, 1, 2, 24)))
h1.Ping(h2)
createHost := func(pos int) (*g.Host. error) {
return n.AddHost(fmt.Sprintf("h%d", pos))
}
linkHosts := func(a, b *g.Node) error {
_, err := n.AddRouter(fmt.Sprintf("r%d", pos),
o.Interface("eth0", a, o.AddressIPv4(10, 0, 0, a.Position, 24),
o.Interface("eth1", b, o.AddressIPv4(10, 0, 0, b.Position, 24)
)
return err
}
topo.Linear(n, 100, createHost, linkHosts)
n.Nodes["h0"].Traceroute(n.Nodes["h99"])
Make network persistent
n, _ := g.NewNetwork("mynet", o.Persistent(true))
/* ... */
Introspect network after creation with gontc
$ gontc list
mynet
$ gontc list mynet
mynet/h1
mynet/h2
$ gontc exec mynet/h1 hostname
h1.mynet.gont
$ gontc shell mynet/h1
$ mynet/h1: ip address show
Usage: gontc [flags] <command>
Supported <commands> are:
identify return the network and node name if gontc
is executed within a network namespace
shell [<network>/]<node> get an interactive shell inside <node>
exec [<network>/]<node> <command> [args] executes a <command> in the
namespace of <node> with optional [args]
list [<network>] list all active Gont networks or nodes
of a given network
clean [<network>] removes the all or just the
specified Gont network
help show this usage information
version shows the version of Gont
Example:
gontc exec zorn/h1 ping h2
Gont - The Go network tester
Author Steffen Vogel <post@steffenvogel>
NET_ADMIN
caps
digraph D {
/* network options */
persistent = true
/* nodes */
h1 [type=host, exec="ping h2"]
h2 [type=host]
r1 [type=router]
/* links */
h1 -> r1 [address="10.0.0.1/24",
mtu=9000]
h2 -> r1 [address="10.0.0.2/24",
mtu=9000]
}
Steffen Vogel
The development of Gont has been supported by the ERIGrid 2.0 project of the H2020 Programme under Grant Agreement No. 870620.