at master 4.1 kB view raw
1{ pkgs, lib, ... }: 2 3let 4 baud = 57600; 5 tty = "/dev/ttyACM0"; 6 port = "tnc0"; 7 socatPort = 1234; 8 9 createAX25Node = nodeId: { 10 boot.kernelModules = [ "ax25" ]; 11 12 networking.firewall.allowedTCPPorts = [ socatPort ]; 13 14 environment.systemPackages = with pkgs; [ 15 libax25 16 ax25-tools 17 ax25-apps 18 socat 19 ]; 20 21 services.ax25.axports."${port}" = { 22 inherit baud tty; 23 enable = true; 24 callsign = "NOCALL-${toString nodeId}"; 25 description = "mocked tnc"; 26 }; 27 28 services.ax25.axlisten = { 29 enable = true; 30 }; 31 32 # All mocks radios will connect back to socat-broker on node 1 in order to get 33 # all messages that are "broadcasted over the ether" 34 systemd.services.ax25-mock-hardware = { 35 description = "mock AX.25 TNC and Radio"; 36 wantedBy = [ "default.target" ]; 37 before = [ 38 "ax25-kissattach-${port}.service" 39 "axlisten.service" 40 ]; 41 after = [ "network.target" ]; 42 serviceConfig = { 43 Type = "exec"; 44 ExecStart = "${pkgs.socat}/bin/socat -d -d tcp:192.168.1.1:${toString socatPort} pty,link=${tty},b${toString baud},raw"; 45 }; 46 }; 47 }; 48in 49{ 50 name = "ax25Simple"; 51 nodes = { 52 node1 = lib.mkMerge [ 53 (createAX25Node 1) 54 # mimicking radios on the same frequency 55 { 56 systemd.services.ax25-mock-ether = { 57 description = "mock radio ether"; 58 wantedBy = [ "default.target" ]; 59 requires = [ "network.target" ]; 60 before = [ "ax25-mock-hardware.service" ]; 61 # broken needs access to "ss" or "netstat" 62 path = [ pkgs.iproute2 ]; 63 serviceConfig = { 64 Type = "exec"; 65 ExecStart = "${pkgs.socat}/bin/socat-broker.sh tcp4-listen:${toString socatPort}"; 66 }; 67 postStart = "${pkgs.coreutils}/bin/sleep 2"; 68 }; 69 } 70 ]; 71 node2 = createAX25Node 2; 72 node3 = createAX25Node 3; 73 }; 74 testScript = 75 { ... }: 76 '' 77 def wait_for_machine(m): 78 m.succeed("lsmod | grep ax25") 79 m.wait_for_unit("ax25-axports.target") 80 m.wait_for_unit("axlisten.service") 81 m.fail("journalctl -o cat -u axlisten.service | grep -i \"no AX.25 port data configured\"") 82 83 # start the first node since the socat-broker needs to be running 84 node1.start() 85 node1.wait_for_unit("ax25-mock-ether.service") 86 wait_for_machine(node1) 87 88 node2.start() 89 node3.start() 90 wait_for_machine(node2) 91 wait_for_machine(node3) 92 93 # Node 1 -> Node 2 94 node1.succeed("echo hello | ax25_call ${port} NOCALL-1 NOCALL-2") 95 node2.sleep(1) 96 node2.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-1 to NOCALL-2 ctl I00\" | grep hello") 97 98 # Node 1 -> Node 3 99 node1.succeed("echo hello | ax25_call ${port} NOCALL-1 NOCALL-3") 100 node3.sleep(1) 101 node3.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-1 to NOCALL-3 ctl I00\" | grep hello") 102 103 # Node 2 -> Node 1 104 # must sleep due to previous ax25_call lingering 105 node2.sleep(5) 106 node2.succeed("echo hello | ax25_call ${port} NOCALL-2 NOCALL-1") 107 node1.sleep(1) 108 node1.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-2 to NOCALL-1 ctl I00\" | grep hello") 109 110 # Node 2 -> Node 3 111 node2.succeed("echo hello | ax25_call ${port} NOCALL-2 NOCALL-3") 112 node3.sleep(1) 113 node3.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-2 to NOCALL-3 ctl I00\" | grep hello") 114 115 # Node 3 -> Node 1 116 # must sleep due to previous ax25_call lingering 117 node3.sleep(5) 118 node3.succeed("echo hello | ax25_call ${port} NOCALL-3 NOCALL-1") 119 node1.sleep(1) 120 node1.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-3 to NOCALL-1 ctl I00\" | grep hello") 121 122 # Node 3 -> Node 2 123 node3.succeed("echo hello | ax25_call ${port} NOCALL-3 NOCALL-2") 124 node2.sleep(1) 125 node2.succeed("journalctl -o cat -u axlisten.service | grep -A1 \"NOCALL-3 to NOCALL-2 ctl I00\" | grep hello") 126 ''; 127}