aboutsummaryrefslogtreecommitdiffstats
path: root/test/packetdrill/script.h
blob: be4944a528172ed13e8c3195ec6078213f6737ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*
 * Copyright 2013 Google Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */
/*
 * Author: ncardwell@google.com (Neal Cardwell)
 *
 * Type definitions for data structures to represent a parsed test script.
 */

#ifndef __SCRIPT_H__
#define __SCRIPT_H__

#include "types.h"

#include <sys/time.h>
#include "packet.h"

#define MSGHDR_MAX_CONTROLLEN 1000	/* arbitrary maximum cmsg length */

/* The types of expressions in a script */
enum expression_t {
	EXPR_ELLIPSIS,		  /* ... but no value */
	EXPR_INTEGER,		  /* integer in 'num' */
	EXPR_LINGER,		  /* struct linger for SO_LINGER */
	EXPR_WORD,		  /* unquoted word in 'string' */
	EXPR_STRING,		  /* double-quoted string in 'string' */
	EXPR_GRE,		  /* GRE header */
	EXPR_IN6_ADDR,		  /* in6_addr in 'address_ipv6' */
	EXPR_SOCKET_ADDRESS_IPV4, /* sockaddr_in in 'socket_address_ipv4' */
	EXPR_SOCKET_ADDRESS_IPV6, /* sockaddr_in6 in 'socket_address_ipv6' */
	EXPR_BINARY,		  /* binary expression, 2 sub-expressions */
	EXPR_LIST,		  /* list of expressions */
	EXPR_IOVEC,		  /* expression tree for an iovec struct */
	EXPR_MSGHDR,		  /* expression tree for a msghdr struct */
	EXPR_CMSG,		  /* expression tree for a cmsg struct */
	EXPR_POLLFD,		  /* expression tree for a pollfd struct */
	EXPR_MPLS_STACK,	  /* MPLS label stack expression */
	EXPR_SCM_TIMESTAMPING,	  /* scm_timestamping expression */
	EXPR_SOCK_EXTENDED_ERR,	  /* scm_sock_extended_err expression */
	EXPR_EPOLLEV,	          /* expression tree for a epoll_event struct */
	NUM_EXPR_TYPES,
};
/* Convert an expression type to a human-readable string */
const char *expression_type_to_string(enum expression_t type);

/* An expression in a script */
struct expression {
	enum expression_t type;
	union {
		s64 num;
		char *string;
		struct linger linger;
		struct gre gre;
		struct in6_addr address_ipv6;
		struct sockaddr_in *socket_address_ipv4;
		struct sockaddr_in6 *socket_address_ipv6;
		struct binary_expression *binary;
		struct expression_list *list;
		struct iovec_expr *iovec;
		struct msghdr_expr *msghdr;
		struct cmsg_expr *cmsg;
		struct pollfd_expr *pollfd;
		struct mpls_stack *mpls_stack;
		struct scm_timestamping_expr *scm_timestamping;
		struct sock_extended_err_expr *sock_extended_err;
		struct epollev_expr *epollev;
	} value;
	const char *format;	/* the printf format for printing the value */
};

/* Two expressions combined via a binary operator */
struct binary_expression {
	char *op;			/* binary operator */
	struct expression *lhs;	/* left hand side expression */
	struct expression *rhs;	/* right hand side expression */
};

/* A list of expressions, e.g. a list of actual parameters in function call,
 * or list of elements in an array.
 */
struct expression_list {
	struct expression *expression;
	struct expression_list *next;
};

/* Parse tree for a iovec struct in a writev/readv/sendmsg/recvmsg syscall. */
struct iovec_expr {
	struct expression *iov_base;
	struct expression *iov_len;
};

/* Parse tree for a msghdr struct in a sendmsg/recvmsg syscall. */
struct msghdr_expr {
	struct expression *msg_name;
	struct expression *msg_namelen;
	struct expression *msg_iov;
	struct expression *msg_iovlen;
	struct expression *msg_control;
	struct expression *msg_flags;
};

/* Parse tree for a cmsg item in a sendmsg/recvmsg syscall. */
struct cmsg_expr {
	struct expression *cmsg_level;
	struct expression *cmsg_type;
	struct expression *cmsg_data;
};

/* A verbatim copy of Linux's struct scm_timestamping for portability. */
struct scm_timestamping_expr {
	struct timespec ts[3];
};

/* Parse tree for a sock_extended_err item in a recvmsg syscall. */
struct sock_extended_err_expr {
	struct expression *ee_errno;
	struct expression *ee_origin;
	struct expression *ee_type;
	struct expression *ee_code;
	struct expression *ee_info;
	struct expression *ee_data;
};

/* Parse tree for a pollfd struct in a poll syscall. */
struct pollfd_expr {
	struct expression *fd;		/* file descriptor */
	struct expression *events;	/* requested events */
	struct expression *revents;	/* returned events */
};

/* Parse tree for a epoll_event struct in an epoll syscall. */
struct epollev_expr {
	struct expression *events;
	struct expression *ptr;
	struct expression *fd;
	struct expression *u32;
	struct expression *u64;
};

/* The errno-related info from strace to summarize a system call error */
struct errno_spec {
	const char *errno_macro;	/* errno symbol (C macro name) */
	const char *strerror;		/* strerror translation of errno */
};

/* A system call and its expected result. System calls that should
 * return immediately have an end_usecs value of SYSCALL_NON_BLOCKING.
 * System calls that block for some non-zero time have a non-negative
 * end_usecs indicating the time at which the system call should
 * return.
 */
struct syscall_spec {
	const char *name;			/* name of system call */
	struct expression_list *arguments;	/* arguments to system call */
	struct expression *result;		/* expected result from call */
	struct errno_spec *error;		/* errno symbol or NULL */
	char *note;				/* extra note from strace */
	s64 end_usecs;				/* finish time, if it blocks */
};
#define SYSCALL_NON_BLOCKING  -1		/* end_usecs if non-blocking */

static inline bool is_blocking_syscall(struct syscall_spec *syscall)
{
	return syscall->end_usecs != SYSCALL_NON_BLOCKING;
}

/* A shell command line to execute using system(3) */
struct command_spec {
	const char *command_line;	/* executed with /bin/sh */
};

/* An ASCII text snippet of code to insert in the post-processing
 * output. This can be, for example, a snippet of Python to execute.
 */
struct code_spec {
	const char *text;	/* snippet of post-processing code */
};

/* Types of events in a script */
enum event_t {
	INVALID_EVENT = 0,
	PACKET_EVENT,
	SYSCALL_EVENT,
	COMMAND_EVENT,
	CODE_EVENT,
	NUM_EVENT_TYPES,
};

/* Types of event times */
enum event_time_t {
	ABSOLUTE_TIME = 0,
	RELATIVE_TIME,
	ANY_TIME,
	ABSOLUTE_RANGE_TIME,
	RELATIVE_RANGE_TIME,
	NUM_TIME_TYPES,
};

/* An event in a script */
struct event {
	int line_number;	/* location in test script file */
	s64 time_usecs;		/* event time in microseconds */
	s64 time_usecs_end;	/* event time range end (or NO_TIME_RANGE) */
	s64 offset_usecs;	/* relative event time offset from script start
				 * (or NO_TIME_RANGE) */
	enum event_time_t time_type; /* type of time */
	enum event_t type;	/* type of the event */
	union {
		struct packet	*packet;
		struct syscall_spec	*syscall;
		struct command_spec	*command;
		struct code_spec	*code;
	} event;		/* pointer to the event */
	struct event *next;	/* next in linked list of events */
};
#define NO_TIME_RANGE	-1		/* time_usecs_end if no range */

static inline bool is_event_time_absolute(struct event *event)
{
	return ((event->time_type == ABSOLUTE_TIME) ||
		(event->time_type == ABSOLUTE_RANGE_TIME));
}

/* A --name=value option in a script */
struct option_list {
	char *name;
	char *value;
	struct option_list *next;
};

/* A parsed script. The script owns all of the data to which
 * it points. TODO: add a script_free() to free everything when we are
 * done executing the script, instead of leaking all that memory.
 */
struct script {
	struct option_list *option_list;    /* linked list of options */
	struct command_spec *init_command;  /* untimed initialization command */
	struct event	*event_list;	    /* linked list of all events */
	struct command_spec *cleanup_command;  /* untimed cleanup command */
	char		*buffer;	    /* raw input text of the script */
	int		length;		    /* number of bytes in the script */
};

/* Global pointer for final command we always execute at end of script: */
extern const char *cleanup_cmd;
/* Path of currently-executing script, for use in cleanup command errors: */
extern const char *script_path;

/* A table entry mapping a bit mask to its human-readable name.
 * A table of such mappings must be terminated with a struct with a
 * NULL name.
 */
struct flag_name {
	u64		flag;	/* a flag with one bit set */
	const char	*name;	/* human-readable ASCII name for this bit */
};

/* Initialize a script object */
extern void init_script(struct script *script);

/* Look up the value of the given symbol, and fill it in. On success,
 * return STATUS_OK; if the symbol cannot be found, return
 * STATUS_ERR and fill in an error message in *error.
 */
extern int symbol_to_int(const char *input_symbol, s64 *output_integer,
			 char **error);

/* Convert the given bit flags to a human-readable ASCII bit-wise OR
 * ('|') expression and return the resulting malloc-allocated
 * string. Caller must free() the memory.
 */
extern struct flag_name poll_flags[];
char *flags_to_string(struct flag_name *flags_array, u64 flags);

/* Do a deep deallocation of a heap-allocated expression list,
 * including any other space that it points too.
 */
extern void free_expression(struct expression *expression);

/* Do a deep deallocation of a heap-allocated expression list,
 * including any other space that it points too.
 */
extern void free_expression_list(struct expression_list *list);

/* Return a copy of the given expression list with each expression
 * evaluated (e.g. symbols resolved to ints). On success, returns
 * STATUS_OK. On error return STATUS_ERR and fill in *error.
 */
extern int evaluate_expression_list(struct expression_list *in_list,
				    struct expression_list **out_list,
				    char **error);

#endif /* __SCRIPT_H__ */