GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/switchctl/switchctl.c Lines: 0 141 0.0 %
Date: 2017-11-07 Branches: 0 102 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: switchctl.c,v 1.7 2017/01/31 05:53:08 jsg Exp $	*/
2
3
/*
4
 * Copyright (c) 2007-2015 Reyk Floeter <reyk@openbsd.org>
5
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7
 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
#include <sys/types.h>
23
#include <sys/socket.h>
24
#include <sys/queue.h>
25
#include <sys/un.h>
26
#include <sys/tree.h>
27
28
#include <err.h>
29
#include <errno.h>
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <string.h>
33
#include <syslog.h>
34
#include <unistd.h>
35
#include <event.h>
36
#include <pwd.h>
37
38
#include "switchd.h"
39
#include "parser.h"
40
41
__dead void	 usage(void);
42
43
struct imsgname {
44
	int type;
45
	char *name;
46
	void (*func)(struct imsg *);
47
};
48
49
int		 show_summary_msg(struct imsg *, int);
50
51
struct imsgname *monitor_lookup(uint8_t);
52
void		 monitor_id(struct imsg *);
53
int		 monitor(struct imsg *);
54
55
int		 ca_opt(struct parse_result *);
56
57
struct imsgname imsgs[] = {
58
	{ IMSG_CTL_OK,			"ok",			NULL },
59
	{ IMSG_CTL_FAIL,		"fail",			NULL },
60
	{ IMSG_CTL_VERBOSE,		"verbose",		NULL },
61
	{ IMSG_CTL_RELOAD,		"reload",		NULL },
62
	{ IMSG_CTL_RESET,		"reset",		NULL },
63
	{ 0,				NULL,			NULL }
64
65
};
66
struct imsgname imsgunknown = {
67
	-1,				"<unknown>",		NULL
68
};
69
70
struct imsgbuf	*ibuf;
71
72
__dead void
73
usage(void)
74
{
75
	extern char *__progname;
76
77
	fprintf(stderr, "usage: %s [-q] [-s socket] command [arg ...]\n",
78
	    __progname);
79
	exit(1);
80
}
81
82
int
83
main(int argc, char *argv[])
84
{
85
	struct sockaddr_un	 sun;
86
	struct parse_result	*res;
87
	struct imsg		 imsg;
88
	struct switch_client	 swc;
89
	struct switch_address	*to;
90
	struct passwd		*pw;
91
	int			 ctl_sock;
92
	int			 done = 1;
93
	int			 n;
94
	int			 ch;
95
	int			 v = 0;
96
	int			 quiet = 0;
97
	int			 verbose = 0;
98
	const char		*sock = SWITCHD_SOCKET;
99
100
	while ((ch = getopt(argc, argv, "qs:v")) != -1) {
101
		switch (ch) {
102
		case 'q':
103
			quiet = 1;
104
			break;
105
		case 's':
106
			sock = optarg;
107
			break;
108
		case 'v':
109
			verbose = 2;
110
			break;
111
		default:
112
			usage();
113
			/* NOTREACHED */
114
		}
115
	}
116
	argc -= optind;
117
	argv += optind;
118
119
	if ((pw = getpwnam(SWITCHD_USER)) == NULL)
120
		fatal("switchctl: getpwnam");
121
122
	/*
123
	 * pledge in switchctl:
124
	 * stdio - for malloc and basic I/O including events.
125
	 * dns - for parsehostport() in the device spec.
126
	 * inet - for handling tcp connections with OpenFlow peers.
127
	 * unix - for opening the control socket.
128
	 */
129
	if (pledge("stdio dns inet unix flock rpath cpath wpath", NULL) == -1)
130
		err(1, "pledge");
131
132
	log_init(quiet ? 0 : 2, LOG_USER);
133
134
	/* parse options */
135
	if ((res = parse(argc, argv)) == NULL)
136
		exit(1);
137
138
	res->quiet = quiet;
139
	res->verbose = verbose;
140
141
	if (res->quiet && res->verbose)
142
		fatal("conflicting -v and -q options");
143
144
	switch (res->action) {
145
	case NONE:
146
		usage();
147
		break;
148
	case DUMP_DESC:
149
	case DUMP_FEATURES:
150
	case DUMP_FLOWS:
151
	case DUMP_TABLES:
152
	case FLOW_ADD:
153
	case FLOW_DELETE:
154
	case FLOW_MODIFY:
155
		ofpclient(res, pw);
156
		break;
157
	default:
158
		goto connect;
159
	}
160
161
	return (0);
162
163
 connect:
164
	/* connect to sdnflowd control socket */
165
	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
166
		err(1, "socket");
167
168
	bzero(&sun, sizeof(sun));
169
	sun.sun_family = AF_UNIX;
170
	strlcpy(sun.sun_path, sock, sizeof(sun.sun_path));
171
 reconnect:
172
	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
173
		/* Keep retrying if running in monitor mode */
174
		if (res->action == MONITOR &&
175
		    (errno == ENOENT || errno == ECONNREFUSED)) {
176
			usleep(100);
177
			goto reconnect;
178
		}
179
		err(1, "connect: %s", sock);
180
	}
181
182
	if (res->ibuf != NULL)
183
		ibuf = res->ibuf;
184
	else
185
		if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
186
			err(1, "malloc");
187
	imsg_init(ibuf, ctl_sock);
188
189
	/* process user request */
190
	switch (res->action) {
191
	case RESETALL:
192
		v = RESET_ALL;
193
		break;
194
	case LOG_VERBOSE:
195
		v = 2;
196
		break;
197
	case LOG_BRIEF:
198
	default:
199
		v = 0;
200
		break;
201
	}
202
203
	switch (res->action) {
204
	case NONE:
205
		usage();
206
		/* NOTREACHED */
207
		break;
208
	case SHOW_SUM:
209
	case SHOW_SWITCHES:
210
	case SHOW_MACS:
211
		imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0);
212
		printf("%-4s\t%-4s\t%-8s\t%-24s\t%s\n",
213
		    "Switch", "Port", "Type", "Name", "Info");
214
		done = 0;
215
		break;
216
	case CONNECT:
217
	case DISCONNECT:
218
		memset(&swc, 0, sizeof(swc));
219
		if (res->addr.ss_family == AF_UNSPEC)
220
			errx(1, "invalid address");
221
222
		memcpy(&swc.swc_addr.swa_addr, &res->addr, sizeof(res->addr));
223
		if (res->action == DISCONNECT) {
224
			imsg_compose(ibuf, IMSG_CTL_DISCONNECT, 0, 0, -1,
225
			    &swc, sizeof(swc));
226
			break;
227
		}
228
229
		to = &swc.swc_target;
230
		memcpy(to, &res->uri, sizeof(*to));
231
232
		imsg_compose(ibuf, IMSG_CTL_CONNECT, 0, 0, -1,
233
		    &swc, sizeof(swc));
234
		break;
235
	case RESETALL:
236
		imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, &v, sizeof(v));
237
		printf("reset request sent.\n");
238
		break;
239
	case LOAD:
240
		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1,
241
		    res->path, strlen(res->path));
242
		break;
243
	case RELOAD:
244
		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
245
		break;
246
	case MONITOR:
247
		imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0);
248
		done = 0;
249
		break;
250
	case LOG_VERBOSE:
251
	case LOG_BRIEF:
252
		imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &v, sizeof(v));
253
		printf("logging request sent.\n");
254
		break;
255
	default:
256
		break;
257
	}
258
259
	while (ibuf->w.queued)
260
		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
261
			err(1, "write error");
262
263
	while (!done) {
264
		if ((n = imsg_read(ibuf)) == -1)
265
			errx(1, "imsg_read error");
266
		if (n == 0)
267
			errx(1, "pipe closed");
268
269
		while (!done) {
270
			if ((n = imsg_get(ibuf, &imsg)) == -1)
271
				errx(1, "imsg_get error");
272
			if (n == 0)
273
				break;
274
			switch (res->action) {
275
			case SHOW_SUM:
276
			case SHOW_SWITCHES:
277
			case SHOW_MACS:
278
				done = show_summary_msg(&imsg, res->action);
279
				break;
280
			case MONITOR:
281
				done = monitor(&imsg);
282
				break;
283
			default:
284
				break;
285
			}
286
			imsg_free(&imsg);
287
		}
288
	}
289
	close(ctl_sock);
290
	free(ibuf);
291
292
	return (0);
293
}
294
295
int
296
show_summary_msg(struct imsg *imsg, int type)
297
{
298
	struct switch_control	*sw;
299
	struct macaddr		*mac;
300
	struct timeval		 tv;
301
	static unsigned int	 sw_id = 0;
302
303
	switch (imsg->hdr.type) {
304
	case IMSG_CTL_SWITCH:
305
		IMSG_SIZE_CHECK(imsg, sw);
306
		sw = imsg->data;
307
		sw_id = sw->sw_id;
308
309
		if (!(type == SHOW_SUM || type == SHOW_SWITCHES))
310
			break;
311
		printf("%-4u\t%-4s\t%-8s\t%-24s\n",
312
		    sw->sw_id, "", "switch",
313
		    print_host(&sw->sw_addr, NULL, 0));
314
		break;
315
	case IMSG_CTL_MAC:
316
		IMSG_SIZE_CHECK(imsg, mac);
317
		mac = imsg->data;
318
319
		if (!(type == SHOW_SUM || type == SHOW_MACS))
320
			break;
321
322
		getmonotime(&tv);
323
		printf("%-4u\t%-4u\t%-8s\t%-24s\tage %llds\n",
324
		    sw_id, mac->mac_port, "mac",
325
		    print_ether(mac->mac_addr),
326
		    (long long)tv.tv_sec - mac->mac_age);
327
		break;
328
	case IMSG_CTL_END:
329
		return (1);
330
	default:
331
		errx(1, "wrong message in summary: %u", imsg->hdr.type);
332
		break;
333
	}
334
	return (0);
335
}
336
337
struct imsgname *
338
monitor_lookup(uint8_t type)
339
{
340
	int i;
341
342
	for (i = 0; imsgs[i].name != NULL; i++)
343
		if (imsgs[i].type == type)
344
			return (&imsgs[i]);
345
	return (&imsgunknown);
346
}
347
348
int
349
monitor(struct imsg *imsg)
350
{
351
	time_t			 now;
352
	int			 done = 0;
353
	struct imsgname		*imn;
354
355
	now = time(NULL);
356
357
	imn = monitor_lookup(imsg->hdr.type);
358
	printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name,
359
	    imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid);
360
	printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now));
361
	if (imn->type == -1)
362
		done = 1;
363
	if (imn->func != NULL)
364
		(*imn->func)(imsg);
365
366
	return (done);
367
}