test(vm/containers): build network topology with containers
get rid of mininet
This commit is contained in:
parent
f49c90308f
commit
7fa5d010ba
4 changed files with 291 additions and 80 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,3 @@
|
||||||
/target
|
/target
|
||||||
.direnv
|
.direnv
|
||||||
.envrc
|
.envrc
|
||||||
nixos.qcow2
|
|
||||||
|
|
66
mn.py
66
mn.py
|
@ -1,66 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
from mininet.topo import Topo
|
|
||||||
from mininet.net import Mininet
|
|
||||||
from mininet.util import dumpNodeConnections
|
|
||||||
from mininet.log import setLogLevel
|
|
||||||
|
|
||||||
class CustomTopo(Topo):
|
|
||||||
"Single switch connected to n hosts."
|
|
||||||
def build(self):
|
|
||||||
client_vnis = list(range(1000, 1004))
|
|
||||||
vtep_count = 2
|
|
||||||
|
|
||||||
switch = self.addSwitch('s0')
|
|
||||||
vault01 = self.addHost('a1')
|
|
||||||
self.addLink(vault01, switch)
|
|
||||||
|
|
||||||
vteps = []
|
|
||||||
for i in range(vtep_count):
|
|
||||||
vteps.append(self.addHost('s%s' % (i+1)))
|
|
||||||
self.addLink(node1=vteps[i], node2=switch, port1=0)
|
|
||||||
|
|
||||||
vtepCmds = []
|
|
||||||
for vni in range(1000, 1004):
|
|
||||||
for i in range(vtep_count):
|
|
||||||
vtep_name = 's%s' % (i+1)
|
|
||||||
vtepCmds.append((vtep_name, 'ip link add name s%s-vtep%s type vxlan dev s%s-eth0 id %s dstport 4789 srcport 4789 4789 remote 10.0.0.1' % (i+1, vni, i+1, vni)))
|
|
||||||
vtepCmds.append((vtep_name, 'ip link set s%s-vtep%s up' % (i+1, vni)))
|
|
||||||
vtepCmds.append((vtep_name, 'ip link add name s%s-br%s type bridge' % (i+1, vni)))
|
|
||||||
vtepCmds.append((vtep_name, 'ip link set s%s-br%s up' % (i+1, vni)))
|
|
||||||
vtepCmds.append((vtep_name, 'ip link set dev s%s-vtep%s master s%s-br%s'% (i+1, vni, i+1, vni)))
|
|
||||||
vtepCmds.append((vtep_name, 'ip link set dev s%s-eth%s master s%s-br%s' % (i+1, vni, i+1, vni)))
|
|
||||||
|
|
||||||
host = self.addHost('vni%ss%s' % (vni, i + 1))
|
|
||||||
self.addLink(node1=host, node2=vteps[i], port2=vni)
|
|
||||||
|
|
||||||
|
|
||||||
self.vtepCmds = vtepCmds
|
|
||||||
|
|
||||||
def simpleTest():
|
|
||||||
"Create and test a simple network"
|
|
||||||
topo = CustomTopo()
|
|
||||||
net = Mininet(topo)
|
|
||||||
net.start()
|
|
||||||
print( "Dumping host connections" )
|
|
||||||
dumpNodeConnections(net.hosts)
|
|
||||||
for e in topo.vtepCmds:
|
|
||||||
print(net.get(e[0]).cmd(e[1]))
|
|
||||||
print(">>>")
|
|
||||||
print(net.get("s1").cmd("ip a"))
|
|
||||||
print(">>>")
|
|
||||||
print(net.get("s2").cmd("ip a"))
|
|
||||||
print(">>>")
|
|
||||||
print(net.get("a1").cmd("ip a"))
|
|
||||||
|
|
||||||
print(net.get("a1").cmd("tcpdump > /tmp/tcp &"))
|
|
||||||
print(net.get("vni1000s1").cmd("ping -c 1 10.0.0.5"))
|
|
||||||
print(net.get("a1").cmd("kill $!"))
|
|
||||||
print(net.get("a1").cmd("cat /tmp/tcp"))
|
|
||||||
|
|
||||||
net.stop()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# Tell mininet to print useful information
|
|
||||||
setLogLevel('info')
|
|
||||||
simpleTest()
|
|
31
vm/common.nix
Normal file
31
vm/common.nix
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{ pkgs, lib, config, ... }: {
|
||||||
|
environment.defaultPackages = [
|
||||||
|
pkgs.inetutils
|
||||||
|
pkgs.tcpdump
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.useNetworkd = true;
|
||||||
|
systemd.network.enable = true;
|
||||||
|
|
||||||
|
nix = {
|
||||||
|
nixPath = [
|
||||||
|
"nixpkgs=${toString <nixpkgs>}"
|
||||||
|
];
|
||||||
|
channel.enable = false;
|
||||||
|
settings = {
|
||||||
|
nix-path = config.nix.nixPath;
|
||||||
|
experimental-features = [
|
||||||
|
"pipe-operator"
|
||||||
|
"nix-command"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
package = pkgs.lix;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.root = {
|
||||||
|
password = "vxlan";
|
||||||
|
initialHashedPassword = lib.mkForce null;
|
||||||
|
};
|
||||||
|
|
||||||
|
system.stateVersion = "25.05";
|
||||||
|
}
|
273
vm/vm.nix
273
vm/vm.nix
|
@ -1,27 +1,274 @@
|
||||||
{ pkgs, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
imap
|
||||||
|
flatten
|
||||||
|
listToAttrs
|
||||||
|
;
|
||||||
|
access-topology = [
|
||||||
|
[
|
||||||
|
1000
|
||||||
|
1001
|
||||||
|
1002
|
||||||
|
1003
|
||||||
|
]
|
||||||
|
[
|
||||||
|
1000
|
||||||
|
1001
|
||||||
|
1002
|
||||||
|
1003
|
||||||
|
]
|
||||||
|
];
|
||||||
|
br_name = sw: vni: "sw${toString sw}-vni${toString vni}";
|
||||||
|
client_name = sw: vni: "h-${br_name sw vni}";
|
||||||
|
vtep_name = sw: vni: "v-${toString sw}-${toString vni}";
|
||||||
|
sw_name = sw: "sw${toString sw}";
|
||||||
|
|
||||||
|
vtep_br_name = sw: vni: "br${vtep_name sw vni}";
|
||||||
|
vtep_vxlan_name = sw: vni: "x${vtep_name sw vni}";
|
||||||
|
|
||||||
|
clients =
|
||||||
|
listToAttrs
|
||||||
|
<| flatten
|
||||||
|
<| imap (
|
||||||
|
sw:
|
||||||
|
map (vni: {
|
||||||
|
name = client_name sw vni;
|
||||||
|
value = {
|
||||||
|
privateNetwork = true;
|
||||||
|
ephemeral = true;
|
||||||
|
hostBridge = br_name sw vni;
|
||||||
|
autoStart = true;
|
||||||
|
config = {
|
||||||
|
imports = [ ./common.nix ];
|
||||||
|
networking.hostName = client_name sw vni;
|
||||||
|
services.resolved.enable = false;
|
||||||
|
systemd.network.networks = {
|
||||||
|
"10-eth0" = {
|
||||||
|
name = "eth0";
|
||||||
|
address = [ "10.0.${toString sw}.${toString (vni - 999)}/16" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
) access-topology;
|
||||||
|
switchs =
|
||||||
|
listToAttrs
|
||||||
|
<| imap (sw: vnis: {
|
||||||
|
name = sw_name sw;
|
||||||
|
value = {
|
||||||
|
privateNetwork = true;
|
||||||
|
ephemeral = true;
|
||||||
|
hostBridge = "br0";
|
||||||
|
autoStart = true;
|
||||||
|
extraVeths =
|
||||||
|
listToAttrs
|
||||||
|
<| map (vni: {
|
||||||
|
name = vtep_name sw vni;
|
||||||
|
value.hostBridge = br_name sw vni;
|
||||||
|
}) vnis;
|
||||||
|
config = {
|
||||||
|
imports = [ ./common.nix ];
|
||||||
|
networking.hostName = sw_name sw;
|
||||||
|
services.resolved.enable = false;
|
||||||
|
systemd.network = {
|
||||||
|
networks =
|
||||||
|
{
|
||||||
|
"10-eth0" = {
|
||||||
|
name = "eth0";
|
||||||
|
address = [ "10.0.0.${toString (sw + 1)}/24" ];
|
||||||
|
networkConfig.VXLAN = map (vtep_vxlan_name sw) vnis;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// listToAttrs (
|
||||||
|
flatten
|
||||||
|
<| map (vni: [
|
||||||
|
{
|
||||||
|
name = "10-${vtep_name sw vni}";
|
||||||
|
value = {
|
||||||
|
name = vtep_name sw vni;
|
||||||
|
networkConfig = {
|
||||||
|
Bridge = vtep_br_name sw vni;
|
||||||
|
|
||||||
|
LinkLocalAddressing = false;
|
||||||
|
LLDP = false;
|
||||||
|
EmitLLDP = false;
|
||||||
|
IPv6AcceptRA = false;
|
||||||
|
IPv6SendRA = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "10-${vtep_br_name sw vni}";
|
||||||
|
value = {
|
||||||
|
name = vtep_br_name sw vni;
|
||||||
|
networkConfig = {
|
||||||
|
LinkLocalAddressing = false;
|
||||||
|
LLDP = false;
|
||||||
|
EmitLLDP = false;
|
||||||
|
IPv6AcceptRA = false;
|
||||||
|
IPv6SendRA = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "10-${vtep_vxlan_name sw vni}";
|
||||||
|
value = {
|
||||||
|
name = vtep_vxlan_name sw vni;
|
||||||
|
networkConfig = {
|
||||||
|
Bridge = vtep_br_name sw vni;
|
||||||
|
|
||||||
|
LinkLocalAddressing = false;
|
||||||
|
LLDP = false;
|
||||||
|
EmitLLDP = false;
|
||||||
|
IPv6AcceptRA = false;
|
||||||
|
IPv6SendRA = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
]) vnis
|
||||||
|
);
|
||||||
|
netdevs = listToAttrs (
|
||||||
|
flatten
|
||||||
|
<| map (vni: [
|
||||||
|
{
|
||||||
|
name = "10-${vtep_br_name sw vni}";
|
||||||
|
value = {
|
||||||
|
netdevConfig = {
|
||||||
|
Name = vtep_br_name sw vni;
|
||||||
|
Kind = "bridge";
|
||||||
|
};
|
||||||
|
bridgeConfig.STP = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "10-${vtep_vxlan_name sw vni}";
|
||||||
|
value = {
|
||||||
|
netdevConfig = {
|
||||||
|
Name = vtep_vxlan_name sw vni;
|
||||||
|
Kind = "vxlan";
|
||||||
|
};
|
||||||
|
vxlanConfig = {
|
||||||
|
VNI = vni;
|
||||||
|
Remote = "10.0.0.1";
|
||||||
|
Local = "10.0.0.${toString (sw + 1)}";
|
||||||
|
DestinationPort = 4789;
|
||||||
|
PortRange = 4789;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
]) vnis
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) access-topology;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
virtualisation = {
|
virtualisation = {
|
||||||
memorySize = 4 * 1024;
|
memorySize = 4 * 1024;
|
||||||
cores = 4;
|
cores = 4;
|
||||||
|
diskImage = null;
|
||||||
|
forwardPorts = [
|
||||||
|
{
|
||||||
|
from = "host";
|
||||||
|
host.port = 2222;
|
||||||
|
guest.port = 22;
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
nixos-shell.mounts = {
|
nixos-shell.mounts = {
|
||||||
mountHome = false;
|
mountHome = false;
|
||||||
extraMounts."/root/vxlan" = {
|
extraMounts."/vxlan" = {
|
||||||
target = ./..;
|
target = ./..;
|
||||||
cache = "none";
|
cache = "none";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.mininet.enable = true;
|
imports = [ ./common.nix ];
|
||||||
users.users.root.packages = [
|
|
||||||
pkgs.inetutils
|
|
||||||
pkgs.tcpdump
|
|
||||||
(pkgs.python3.withPackages (ps: with ps; [
|
|
||||||
mininet-python
|
|
||||||
distutils
|
|
||||||
packaging
|
|
||||||
]))
|
|
||||||
];
|
|
||||||
|
|
||||||
system.stateVersion = "25.05";
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
settings.PermitRootLogin = "yes";
|
||||||
|
};
|
||||||
|
|
||||||
|
containers =
|
||||||
|
{
|
||||||
|
"router" = {
|
||||||
|
privateNetwork = true;
|
||||||
|
ephemeral = true;
|
||||||
|
hostBridge = "br0";
|
||||||
|
bindMounts."/vxlan".hostPath = "/vxlan";
|
||||||
|
autoStart = true;
|
||||||
|
config = {
|
||||||
|
imports = [ ./common.nix ];
|
||||||
|
services.resolved.enable = false;
|
||||||
|
systemd.network.networks = {
|
||||||
|
"10-eth0" = {
|
||||||
|
name = "eth0";
|
||||||
|
address = [ "10.0.0.1/24" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// switchs
|
||||||
|
// clients;
|
||||||
|
|
||||||
|
systemd.network =
|
||||||
|
let
|
||||||
|
brs = [ "br0" ] ++ flatten (imap (sw: map (br_name sw)) access-topology);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
networks =
|
||||||
|
listToAttrs
|
||||||
|
<|
|
||||||
|
map (name: {
|
||||||
|
name = "10-${name}";
|
||||||
|
value = {
|
||||||
|
inherit name;
|
||||||
|
networkConfig = {
|
||||||
|
LinkLocalAddressing = false;
|
||||||
|
LLDP = false;
|
||||||
|
EmitLLDP = false;
|
||||||
|
IPv6AcceptRA = false;
|
||||||
|
IPv6SendRA = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) brs
|
||||||
|
++ flatten (
|
||||||
|
imap (
|
||||||
|
sw:
|
||||||
|
map (vni: {
|
||||||
|
name = "10-${vtep_name sw vni}";
|
||||||
|
value = {
|
||||||
|
name = vtep_name sw vni;
|
||||||
|
networkConfig = {
|
||||||
|
LinkLocalAddressing = false;
|
||||||
|
LLDP = false;
|
||||||
|
EmitLLDP = false;
|
||||||
|
IPv6AcceptRA = false;
|
||||||
|
IPv6SendRA = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
) access-topology
|
||||||
|
);
|
||||||
|
netdevs =
|
||||||
|
listToAttrs
|
||||||
|
<| map (name: {
|
||||||
|
name = "10-${name}";
|
||||||
|
value = {
|
||||||
|
netdevConfig = {
|
||||||
|
Name = name;
|
||||||
|
Kind = "bridge";
|
||||||
|
};
|
||||||
|
bridgeConfig.STP = false;
|
||||||
|
};
|
||||||
|
}) brs;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue