aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/Makefile4
-rw-r--r--tools/demos/crash-test.c303
2 files changed, 305 insertions, 2 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 1108433a..c6ec253f 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -34,8 +34,8 @@ KBUILD_LDFLAGS :=
34KBUILD_CFLAGS += $(call cc-option, -fno-pie) 34KBUILD_CFLAGS += $(call cc-option, -fno-pie)
35KBUILD_CFLAGS += $(call cc-option, -no-pie) 35KBUILD_CFLAGS += $(call cc-option, -no-pie)
36 36
37BINARIES := jailhouse demos/ivshmem-demo 37BINARIES := jailhouse demos/ivshmem-demo demos/crash-test
38targets += jailhouse.o demos/ivshmem-demo.o 38targets += jailhouse.o demos/ivshmem-demo.o demos/crash-test.o
39 39
40ifeq ($(ARCH),x86) 40ifeq ($(ARCH),x86)
41BINARIES += demos/cache-timings 41BINARIES += demos/cache-timings
diff --git a/tools/demos/crash-test.c b/tools/demos/crash-test.c
new file mode 100644
index 00000000..80f5ec6b
--- /dev/null
+++ b/tools/demos/crash-test.c
@@ -0,0 +1,303 @@
1/* Inmate Crash Test Application for Jailhouse Hypervisor
2 *
3 * Description:
4 * Application to test whether the linux inmate cell in Jailhouse hypervisor is
5 * working or whether it has crashed. It can be used to send ICMP network packets
6 * to the linux inmate cell continously from root cell and check for incoming
7 * packets. The destination address will be the network interface created by the
8 * ivshmem-net module. It prints "No response received for packet x" when
9 * no incoming ICMP packet is received from inmate.
10 *
11 * This distribution contains contributions or derivatives under copyright
12 * as follows:
13 *
14 * Copyright (c) 2024, Texas Instruments Incorporated
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * - Redistributions of source code must retain the above copyright notice,
21 * this list of conditions and the following disclaimer.
22 * - Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * - Neither the name of Texas Instruments nor the names of its
26 * contributors may be used to endorse or promote products derived
27 * from this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
33 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
34 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
38 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
39 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Force locale language to be set to English. This avoids issues when doing
42 * text and string processing.
43 *
44 * Authors:
45 * Paresh Bhagat <p-bhagat@ti.com>
46 * Gyan Gupta <g-gupta@ti.com>
47 *
48 * Portions of this code are taken https://github.com/amitsaha/ping
49 * which is licensed under Apache License 2.0
50 */
51
52#include <stdio.h>
53#include <stdlib.h>
54#include <unistd.h>
55#include <sys/wait.h>
56#include <sys/time.h>
57#include <sys/types.h>
58#include <signal.h>
59#include <arpa/inet.h>
60#include <string.h>
61#include <netinet/ip_icmp.h>
62
63#define PACKET_SIZE 4096
64#define ICMP_ECHO 8
65#define TIMEOUT 3
66#define ICMP_DATA_LEN 56
67
68typedef struct {
69 int packet_count;
70 int sleep_time;
71 char ip_address[INET_ADDRSTRLEN];
72 int quiet_mode;
73} program_config;
74
75/* Flag to check whether SIGINT signal is received */
76volatile sig_atomic_t interrupted = 0;
77struct sockaddr_in dest_addr;
78int sockfd;
79static void sigint_handler();
80static void print_usage(const char*);
81static int validate_ipv4_address(const char*);
82static void configure_signal_handler();
83static void print_options(program_config*);
84static unsigned short checksum(void*,int);
85static void create_socket(program_config*);
86static int prepare_icmp_packet();
87static void send_icmp_packet(program_config*);
88static int check_icmp_reply(char*,int);
89char sendpacket[PACKET_SIZE];
90char recvpacket[PACKET_SIZE];
91
92/* Signal handler for SIGINT */
93static void sigint_handler() {
94 interrupted = 1;
95}
96
97/* Checksum for ICMP request packet
98 Calculate 16-bit one's complement sum */
99static unsigned short checksum(void *b, int len) {
100 unsigned short *buf = b;
101 unsigned int sum = 0;
102 unsigned short result;
103 for (sum = 0; len > 1; len -= 2) {
104 sum += *buf++;
105 }
106 if (len == 1) {
107 sum += *(unsigned char *)buf;
108 }
109 sum = (sum >> 16) + (sum & 0xFFFF);
110 sum += (sum >> 16);
111 result = ~sum;
112 return result;
113}
114
115/* Print program usage */
116static void print_usage(const char *program_name) {
117 fprintf(stderr, "Usage: %s -c packet_count -s sleep_time -i ipv4_address -q quiet_mode\n", program_name);
118 fprintf(stderr, "Options:\n");
119 fprintf(stderr, "\t-c\t<packet_count>\t\tnumber of packets to be send before sleep\n");
120 fprintf(stderr, "\t-s\t<sleep time>\t\tsleep time between sending packet_count packets\n");
121 fprintf(stderr, "\t-i\t<destination address>\tdestination ip address (IPv4)\n");
122 fprintf(stderr, "\t-q\t<quiet mode>\t\tsuppress output\n");
123 fprintf(stderr, "\t-h\t<help>\t\t\tsee usage\n");
124}
125
126/* Validate IP address */
127static int validate_ipv4_address(const char *ip_address) {
128 return inet_pton(AF_INET, ip_address, &(dest_addr.sin_addr));
129}
130
131/* Configure SIGINT handler */
132static void configure_signal_handler() {
133 struct sigaction sigterm_action;
134 memset(&sigterm_action, 0, sizeof(sigterm_action));
135 sigterm_action.sa_handler = &sigint_handler;
136 sigemptyset(&sigterm_action.sa_mask);
137 sigterm_action.sa_flags = 0;
138 if (sigaction(SIGINT, &sigterm_action, NULL) == -1) {
139 fprintf(stderr, "Failed to set up SIGINT handler\n");
140 exit(EXIT_FAILURE);
141 }
142}
143
144/* Print user passed config options */
145static void print_options(program_config *config) {
146 fprintf(stdout, "Options:\n");
147 fprintf(stdout, " Packet Count\t\t%d\n", config->packet_count);
148 fprintf(stdout, " Sleep time\t\t%d\n", config->sleep_time);
149 fprintf(stdout, " Destination IP\t\t%s\n", config->ip_address);
150 fprintf(stdout, " Quiet Mode\t\t%s\n\n", config->quiet_mode ? "On" : "Off");
151}
152
153/* Create a socket */
154static void create_socket(program_config* config) {
155 if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) {
156 perror("socket");
157 exit(EXIT_FAILURE);
158 }
159 memset(&dest_addr, 0, sizeof(dest_addr));
160 dest_addr.sin_family = AF_INET;
161 inet_pton(AF_INET, config->ip_address, &dest_addr.sin_addr);
162}
163
164/* Prepare ICMP echo request packet */
165static int prepare_icmp_packet() {
166 int packetsize;
167 struct icmp *icmp;
168 icmp = (struct icmp*)sendpacket;
169 icmp->icmp_type = ICMP_ECHO;
170 icmp->icmp_code = 0;
171 icmp->icmp_cksum = 0;
172 icmp->icmp_id = getpid();
173 icmp->icmp_seq = 0;
174 /* 8 + 56 (data) = 64 Bytes ICMP header */
175 packetsize = 8 + ICMP_DATA_LEN;
176 /* Calculate ICMP checksum */
177 icmp->icmp_cksum = checksum(icmp, packetsize);
178 return packetsize;
179}
180
181/* Check incoming icmp packet */
182static int check_icmp_reply(char *buf,int len) {
183 int iphdrlen;
184 struct ip *ip;
185 struct icmp *icmp;
186 ip = (struct ip *)buf;
187 iphdrlen = ip->ip_hl << 2;
188 /* Point to the ICMP header */
189 icmp = (struct icmp *)(buf + iphdrlen);
190 /* Total length of ICMP header */
191 len -= iphdrlen;
192 /* Check ICMP header length */
193 if(len < 8) {
194 fprintf(stderr, "ICMP packet length is less than 8\n");
195 return -1;
196 }
197 /* Check type of received packet */
198 if(icmp->icmp_type != ICMP_ECHOREPLY) {
199 return -1;
200 }
201 return 0;
202}
203
204/* Send icmp packets in a loop */
205static void send_icmp_packet(program_config *config) {
206 int response_received = 1;
207 while (!interrupted && response_received) {
208 for (int i = 0; i < config->packet_count && !interrupted && response_received; i++) {
209 response_received = 0;
210 int packetsize = prepare_icmp_packet();
211 /* Send ICMP echo request packet */
212 if (sendto(sockfd, sendpacket, packetsize, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) == -1) {
213 fprintf(stderr, "Sending Packet %d failed for IP address %s.\n", i+1, config->ip_address);
214 break;
215 }
216 config->quiet_mode == 0 ? fprintf(stdout, "Packet %d send successfully.\n", i + 1) : 0 ;
217
218 /* Receive ICMP echo reply packets with timeout */
219 struct timeval timeout;
220 fd_set readfds;
221 FD_ZERO(&readfds);
222 FD_SET(sockfd, &readfds);
223 timeout.tv_sec = TIMEOUT;
224 timeout.tv_usec = 0;
225
226 if ((select(sockfd + 1, &readfds, NULL, NULL, &timeout)) > 0) {
227 /* Receive the ICMP echo reply packet */
228 unsigned int n = recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, NULL, NULL);
229 if (n>0) {
230 if(check_icmp_reply(recvpacket, n) == 0) {
231 config->quiet_mode == 0 ? fprintf(stdout, "Response received for packet %d.\n", i + 1 ) : 0 ;
232 response_received = 1;
233 }
234 else {
235 fprintf(stderr, "Received packet is not an ICMP echo reply.\n");
236 }
237 } else {
238 fprintf(stderr, "Error in receiving packet!.\n");
239 }
240 } else {
241 fprintf(stderr, "No response received for packet %d.\n", i + 1);
242 }
243 }
244 /* Sleep before sending the next bunch of packets */
245 sleep(config->sleep_time);
246 }
247}
248
249int main(int argc, char *argv[]) {
250 program_config config = {0, 0, "", 0};
251
252 /* Parsing command line arguments */
253 int opt;
254 while ((opt = getopt(argc, argv, "c:s:i:qh")) != -1) {
255 switch (opt) {
256 case 'c':
257 config.packet_count = atoi(optarg);
258 if (config.packet_count <= 0) {
259 fprintf(stderr, "Invalid value for packet count. Packet count must be a positive integer.\n");
260 exit(EXIT_FAILURE);
261 }
262 break;
263 case 's':
264 config.sleep_time = atoi(optarg);
265 if (config.sleep_time <= 0) {
266 fprintf(stderr, "Invalid value for sleep time. Sleep time must be a positive integer.\n");
267 exit(EXIT_FAILURE);
268 }
269 break;
270 case 'i':
271 if (!validate_ipv4_address(optarg)) {
272 fprintf(stderr, "Invalid IPv4 address format.\n");
273 exit(EXIT_FAILURE);
274 }
275 snprintf(config.ip_address, sizeof(config.ip_address), "%s", optarg);
276 break;
277 case 'q':
278 config.quiet_mode = 1;
279 break;
280 case 'h':
281 print_usage(argv[0]);
282 exit(EXIT_SUCCESS);
283 default:
284 print_usage(argv[0]);
285 exit(EXIT_FAILURE);
286 }
287 }
288
289 /* Check if all required arguments are provided */
290 if (config.packet_count == 0 || config.sleep_time == 0 || config.ip_address[0] == '\0') {
291 fprintf(stderr, "Missing required arguments.\n");
292 print_usage(argv[0]);
293 exit(EXIT_FAILURE);
294 }
295
296 print_options(&config);
297 configure_signal_handler();
298 create_socket(&config);
299 send_icmp_packet(&config);
300 close(sockfd);
301 printf("Exiting...\n");
302 return 0;
303}