Readme.md
1# TCP Echo Client Demo for MPS2 Cortex-M3 AN385 emulated using QEMU
2This FreeRTOS+TCP example demonstrates a TCP Echo Client which sends
3echo requests to an Echo Server and then receives the echo reply. The
4Echo Client runs on the MPS2 Cortex-M3 AN385 platform emulated using QEMU.
5
6The demo is being run using the following configurations:
71. [ User Networking (SLIRP) ](Readme_UserNetworking.md)
82. [ Tap Networking ](Readme_TapNetworking.md)
Readme_TapNetworking.md
1# TCP Echo Client Demo for MPS2 Cortex-M3 AN385 emulated using QEMU with TAP Networking
2
3## Setup Description
4The demo requires 2 components -
51. Echo Client - The demo in this repository.
61. Echo Server - An external echo server.
7
8We need a Virtual Machine (VM) running Linux OS to run this demo. Echo Client
9runs in the Virtual Machine (VM) and Echo Server runs on the host machine.
10```
11+--------------------------------------------------------+
12| Host Machine |
13| OS - Any |
14| Runs - Echo Server |
15| +--------------------------+ |
16| | Virtual Machine (VM) | |
17| | OS - Linux | |
18| | Runs - Echo Client | |
19| | | |
20| +----------------+ | +----------------+ | |
21| | | | | | | |
22| | | | | | | |
23| | Echo Server | <-------> | Echo Client | | |
24| | | | | | | |
25| | | | | | | |
26| | | | | | | |
27| +----------------+ | +----------------+ | |
28| | | |
29| +--------------------------+ |
30+--------------------------------------------------------+
31```
32
33## Setting up VM
341. Install a Virtual Machine software on your machine. On Windows you can use
35[Oracle VirtualBox](https://www.virtualbox.org/) and on Mac you can use
36[Parallels](https://www.parallels.com/products/desktop/).
372. Launch a Linux VM. We tested using Ubuntu 22.04.
383. Install the following tools in the VM:
39 * [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads).
40 * [qemu-arm-system](https://www.qemu.org/download).
41 * Make (Version 4.3):
42 ```
43 sudo apt install make
44 ```
45 * ipcalc:
46 ```
47 sudo apt install ipcalc
48 ```
49 * brctl:
50 ```
51 sudo apt install bridge-utils
52 ```
534. Clone the source code in the VM:
54 ```shell
55 git clone https://github.com/FreeRTOS/FreeRTOS.git --recurse-submodules --depth 1
56 ```
57
58## Launch Echo Server
59Launch Echo Server on the host machine.
60### Host OS is Linux
61* Install `netcat`:
62 ```
63 sudo apt install netcat
64 ```
65* Start an Echo Server on port 7:
66 ```shell
67 sudo nc -l 7
68 ```
69
70### Host OS is Windows
71* Install [Npcap/Nmap](https://nmap.org/download.html#windows).
72* Start an Echo Server on port 7:
73 ```shell
74 ncat -l 7
75 ```
76
77### Host OS is Mac
78* Install `netcat`:
79 ```shell
80 brew install netcat
81 ```
82* Start an Echo Server on port 7:
83 ```shell
84 nc -l -p 7
85 ```
86
87## Enable Tap Networking in QEMU
88
89The Tap Networking backend makes use of a tap networking device in the host. It offers very good performance and can be configured to create virtually any type of network topology.
90
91The Echo Client in this demo runs in QEMU inside the VM. We need to enable
92tap networking in QEMU to enable the Echo Client to be able to reach the Echo
93Server. Do the following steps in the VM:
94
95
961. Run the `ifconfig` command to find the VM's network interface details:
97```
98enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9001
99 inet 192.168.1.81 netmask 255.255.255.0 broadcast 192.168.15.255
100 inet6 fe80::89c:55ff:fe3d:18ad prefixlen 64 scopeid 0x20<link>
101 ether 0a:9c:55:3d:18:ad txqueuelen 1000 (Ethernet)
102 RX packets 15001255 bytes 11443805826 (11.4 GB)
103 RX errors 0 dropped 0 overruns 0 frame 0
104 TX packets 9248218 bytes 2080385000 (2.0 GB)
105 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
106
107```
108
1092. Define a shell variable `VM_NETWORK_INTERFACE` and set its value to the
110name of the network interface of the VM. For example, in the above output
111of the `ifconfig` command, name of the the network interface is `enp0s3`:
112```shell
113export VM_NETWORK_INTERFACE=enp0s3
114```
115
1163. Define a shell variable `VM_IP_ADDRESS` and set its value to the IP address
117of the VM. For example, in the above output of the `ifconfig` command, IP
118address of the VM is `192.168.1.81`:
119```shell
120export VM_IP_ADDRESS=192.168.1.81
121```
122
1234. Define a shell variable `VM_NETMASK` and set its value to the netmask of
124the VM. For example, in the above output of the `ifconfig` command, netmask
125of the VM is `255.255.255.0`:
126```shell
127export VM_NETMASK=255.255.255.0
128```
129
1305. Calculate the CIDR of the VM from the netmask:
131```shell
132$ ipcalc -b 1.1.1.1 $VM_NETMASK | grep Netmask
133Netmask: 255.255.255.0 = 24
134```
135CIDR is `24` in the above output.
136
1376. Define a shell variable `VM_CIDR` and set its value to the CIDR of the VM
138found in the above step.
139```shell
140export VM_CIDR=24
141```
142
1437. Find the Default Gateway for the VM:
144```shell
145$ ip route show
146default via 192.168.1.254 dev enp0s3 proto dhcp src 192.168.1.81 metric 100
147```
148Default Gateway is `192.168.1.254` in the above output.
149
1508. Define a shell variable `VM_DEFAULT_GATEWAY` and set its value to the
151Default Gateway of the VM found in the above step.
152```shell
153export VM_DEFAULT_GATEWAY=192.168.1.254
154```
155
1569. Find the DNS Server of the VM:
157```shell
158$ grep "nameserver" /etc/resolv.conf
159nameserver 192.168.1.254
160```
161
16210. Define a shell variable `VM_DNS_SERVER` and set its value to the
163DNS Server of the host machine found in the above step.
164```shell
165export VM_DNS_SERVER=192.168.1.254
166```
167
16811. Pick an IP address for the QEMU which is in the same network as the VM.
169This IP address must not be in-use by any other machine on the same network.
170Define a shell variable `QEMU_IP_ADDRESS` and set its value to the
171picked IP Address. For example, run the following command if you picked
172`192.168.1.80`:
173```shell
174export QEMU_IP_ADDRESS=192.168.1.80
175```
176
17712. Pick a MAC address for the QEMU. Define a shell variable `QEMU_MAC_ADDRESS`
178and set its value to the picked MAC Address. For example, run the following
179command if you picked `52:54:00:12:34:AD`:
180```shell
181export QEMU_MAC_ADDRESS=52:54:00:12:34:AD
182```
183
18413. Define a shell variable `ECHO_SERVER_IP_ADDRESS` and set its value to the
185IP address of the Echo Server which is running on the host. For example,
186run the following command if the IP address of the Echo Server is
187`192.168.1.204`:
188```shell
189export ECHO_SERVER_IP_ADDRESS=192.168.1.204
190```
191
19214. Turn off firewall on the VM.
193On Ubuntu run:
194```shell
195sudo ufw disable
196sudo ufw status
197```
198On RedHat/Fedora system run:
199```shell
200sudo systemctl status firewalld
201sudo systemctl stop firewalld
202```
203
20415. Create virtual bridge (virbr0) and virtual NIC (virbr0-nic) to enable
205networking in QEMU.
206```shell
207sudo ip link add virbr0 type bridge
208sudo ip tuntap add dev virbr0-nic mode tap
209
210sudo ip addr add $VM_IP_ADDRESS/$VM_CIDR dev virbr0
211
212sudo brctl addif virbr0 $VM_NETWORK_INTERFACE
213sudo brctl addif virbr0 virbr0-nic
214
215sudo ip link set virbr0 up
216sudo ip link set virbr0-nic up
217
218sudo ip route add default via $VM_DEFAULT_GATEWAY dev virbr0
219```
220
221The following diagram shows the setup:
222```
223+-------------------------------------------------------------------------+
224| Virtual Machine (VM) |
225| |
226| +-------------------------+ | VM NIC (enp0s3)
227| | | Virtual NIC (virbr0-nic) +--+
228| | QEMU +--+ | |
229| | | | +--------------+ | |
230| | | +--------->| virbr0 | ---------->| +--------> Internet
231| | | | +--------------+ | |
232| | +--+ Virtual Bridge | |
233| | | +--+
234| +-------------------------+ |
235| |
236| |
237+-------------------------------------------------------------------------+
238```
239
240## Build and Run
241Do the following steps in the VM where you cloned the code:
242
2431. Set `configIP_ADDR0`-`configIP_ADDR3` in `FreeRTOSConfig.h` to the value
244of `QEMU_IP_ADDRESS`:
245```shell
246echo $QEMU_IP_ADDRESS
247```
248```c
249#define configIP_ADDR0 192
250#define configIP_ADDR1 168
251#define configIP_ADDR2 1
252#define configIP_ADDR3 80
253```
254
2552. Set `configNET_MASK0`-`configNET_MASK3` in `FreeRTOSConfig.h` to the value
256of `VM_NETMASK`:
257```shell
258echo $VM_NETMASK
259```
260```c
261#define configNET_MASK0 255
262#define configNET_MASK1 255
263#define configNET_MASK2 255
264#define configNET_MASK3 0
265```
266
2673. Set `configGATEWAY_ADDR0`-`configGATEWAY_ADDR3` in `FreeRTOSConfig.h` to
268the value of `VM_DEFAULT_GATEWAY`:
269```shell
270echo $VM_DEFAULT_GATEWAY
271```
272```c
273#define configGATEWAY_ADDR0 192
274#define configGATEWAY_ADDR1 168
275#define configGATEWAY_ADDR2 1
276#define configGATEWAY_ADDR3 254
277```
278
2794. Set `configDNS_SERVER_ADDR0`-`configDNS_SERVER_ADDR3` in `FreeRTOSConfig.h`
280to the value of `VM_DNS_SERVER`:
281```shell
282echo $VM_DNS_SERVER
283```
284```c
285#define configDNS_SERVER_ADDR0 192
286#define configDNS_SERVER_ADDR1 168
287#define configDNS_SERVER_ADDR2 1
288#define configDNS_SERVER_ADDR3 254
289```
290
2915. Set `configMAC_ADDR0`-`configMAC_ADDR5` in `FreeRTOSConfig.h` to the value
292of `QEMU_MAC_ADDRESS`:
293```shell
294echo $QEMU_MAC_ADDRESS
295```
296```c
297#define configMAC_ADDR0 0x52
298#define configMAC_ADDR1 0x54
299#define configMAC_ADDR2 0x00
300#define configMAC_ADDR3 0x12
301#define configMAC_ADDR4 0x34
302#define configMAC_ADDR5 0xAD
303```
304
3056. Set `configECHO_SERVER_ADDR0`-`configECHO_SERVER_ADDR3` in `FreeRTOSConfig.h`
306to the value of `ECHO_SERVER_IP_ADDRESS`:
307```shell
308echo $ECHO_SERVER_IP_ADDRESS
309```
310```c
311#define configECHO_SERVER_ADDR0 192
312#define configECHO_SERVER_ADDR1 168
313#define configECHO_SERVER_ADDR2 1
314#define configECHO_SERVER_ADDR3 204
315```
316
3177. The echo server is assumed to be on port 7, which is the standard echo
318protocol port. You can change the port to any other listening port (e.g. 3682 ).
319Set `echoECHO_PORT` to the value of this port.
320
321```c
322#define echoECHO_PORT ( 7 )
323```
324
3258. Build:
326```shell
327make
328```
329
3309. Run:
331```shell
332sudo qemu-system-arm -machine mps2-an385 -cpu cortex-m3 \
333 -kernel ./build/freertos_tcp_mps2_demo.axf \
334 -netdev tap,id=mynet0,ifname=virbr0-nic,script=no \
335 -net nic,macaddr=$QEMU_MAC_ADDRESS,model=lan9118,netdev=mynet0 \
336 -object filter-dump,id=tap_dump,netdev=mynet0,file=/tmp/qemu_tap_dump\
337 -display gtk -m 16M -nographic -serial stdio \
338 -monitor null -semihosting -semihosting-config enable=on,target=native
339```
340
34110. You should see that following output on the terminal of the Echo Server (which
342is running `sudo nc -l 7` or `netcat -l 7` depending on your OS):
343```
3440FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~0123456789:;<=> ?
345@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~0123456789:;<=>?
346@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~0123456789:;<=>?
347@ABCDEFGHIJKLM
348```
349
350## Debug
3511. Build with debugging symbols:
352```
353make DEBUG=1
354```
355
3562. Start QEMU in the paused state waiting for GDB connection:
357```shell
358sudo qemu-system-arm -machine mps2-an385 -cpu cortex-m3 -s -S \
359 -kernel ./build/freertos_tcp_mps2_demo.axf \
360 -netdev tap,id=mynet0,ifname=virbr0-nic,script=no \
361 -net nic,macaddr=$QEMU_MAC_ADDRESS,model=lan9118,netdev=mynet0 \
362 -object filter-dump,id=tap_dump,netdev=mynet0,file=/tmp/qemu_tap_dump\
363 -display gtk -m 16M -nographic -serial stdio \
364 -monitor null -semihosting -semihosting-config enable=on,target=native
365```
366
3673. Run GDB:
368```shell
369$ arm-none-eabi-gdb -q ./build/freertos_tcp_mps2_demo.axf
370
371(gdb) target remote :1234
372(gdb) break main
373(gdb) c
374```
375
3764. The above QEMU command creates a network packet dump in the file
377`/tmp/qemu_tap_dump` which you can examine using `tcpdump` or WireShark:
378```shell
379sudo tcpdump -r /tmp/qemu_tap_dump | less
380```
381
Readme_UserNetworking.md
1# TCP Echo Client Demo for MPS2 Cortex-M3 AN385 emulated using QEMU with User Mode Networking
2
3## Setup Description
4The demo requires 2 components -
51. Echo Client - The demo in this repository.
61. Echo Server - An echo server.
7
8```
9+--------------------------------------------------------+
10| Host Machine |
11| OS - Any |
12| Runs - Echo Server |
13| +--------------------------+ |
14| | | |
15| | QEMU | |
16| | Runs - Echo Client | |
17| | | |
18| +----------------+ | +----------------+ | |
19| | | | | | | |
20| | | | | | | |
21| | Echo Server | <-------> | Echo Client | | |
22| | | | | | | |
23| | | | | | | |
24| | | | | | | |
25| +----------------+ | +----------------+ | |
26| | | |
27| +--------------------------+ |
28+--------------------------------------------------------+
29```
30
31## PreRequisites
32
331. Install the following tools in the Host Machine:
34 * [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads).
35 * [qemu-arm-system](https://www.qemu.org/download).
36 * Make (Version 4.3):
37 ```
38 sudo apt install make
39 ```
402. Clone the source code:
41 ```
42 git clone https://github.com/FreeRTOS/FreeRTOS.git --recurse-submodules --depth 1
43 ```
44
45## Launch Echo Server
46Launch Echo Server on the host machine.
47
48### Host OS is Linux
49* Install `netcat`:
50 ```
51 sudo apt install netcat
52 ```
53* Start an Echo Server on port 7:
54 ```shell
55 sudo nc -l 7
56 ```
57
58### Host OS is Windows
59* Install [Npcap/Nmap](https://nmap.org/download.html#windows).
60* Start an Echo Server on port 7:
61 ```shell
62 ncat -l 7
63 ```
64
65### Host OS is Mac
66* Install `netcat`:
67 ```shell
68 brew install netcat
69 ```
70* Start an Echo Server on port 7:
71 ```shell
72 nc -l -p 7
73 ```
74
75## Enable User Mode Networking in QEMU
76
77The User Mode Networking is implemented using *slirp*, which provides a full
78TCP/IP stack within QEMU and uses it to implement a virtual NAT network. It does
79not require Administrator privileges.
80
81User Mode Networking has the following limitations:
82
83 - The performance is not very good because of the overhead involved..
84 - ICMP does not work out of the box i.e. you cannot use ping within the guest.
85 Linux hosts require one time setup by root to make ICMP work within the
86 guest.
87 - The guest is not directly accessible from the host or the external network.
88
89
90## Build and Run
91Do the following steps on the host machine:
92
931. The echo server is assumed to be on port 7, which is the standard echo
94protocol port. You can change the port to any other listening port (e.g. 3682 ).
95Set `echoECHO_PORT` to the value of this port.
96
97```c
98#define echoECHO_PORT ( 7 )
99```
100
1012. Build:
102```shell
103 make
104```
105
1063. Run:
107```shell
108 sudo qemu-system-arm -machine mps2-an385 -cpu cortex-m3 \
109 -kernel ./build/freertos_tcp_mps2_demo.axf \
110 -monitor null -semihosting -semihosting-config enable=on,target=native -serial stdio -nographic \
111 -netdev user,id=mynet0, -net nic,model=lan9118,netdev=mynet0
112
113```
114
1156. You should see that following output on the terminal of the Echo Server (which
116is running `sudo nc -l 7` or `netcat -l 7` or `nc -l -p 7` depending on your OS):
117```
1180FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~0123456789:;<=> ?
119@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~0123456789:;<=>?
120@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~0123456789:;<=>?
121@ABCDEFGHIJKLM
122```
123
124## Debug
1251. Build with debugging symbols:
126```
127 make DEBUG=1
128```
129
1302. Start QEMU in the paused state waiting for GDB connection:
131```shell
132 sudo qemu-system-arm -machine mps2-an385 -cpu cortex-m3 -s -S \
133 -kernel ./build/freertos_tcp_mps2_demo.axf \
134 -monitor null -semihosting -semihosting-config enable=on,target=native -serial stdio -nographic \
135 -netdev user,id=mynet0, -net nic,model=lan9118,netdev=mynet0 \
136 -object filter-dump,id=tap_dump,netdev=mynet0,file=/tmp/qemu_tap_dump
137```
138
1393. Run GDB:
140```shell
141sudo arm-none-eabi-gdb -q ./build/freertos_tcp_mps2_demo.axf
142
143(gdb) target remote :1234
144(gdb) break main
145(gdb) c
146```
147
1484. The above QEMU command creates a network packet dump in the file
149`/tmp/qemu_tap_dump` which you can examine using `tcpdump` or WireShark:
150```shell
151sudo tcpdump -r /tmp/qemu_tap_dump | less
152```
153