Skip to content

Commit 3aaf276

Browse files
markjdbbsdjhb
authored andcommitted
bhyve/slirp: Use a dgram socket instead of a seqpacket socket
FreeBSD main has a number of improvements to SEQPACKET sockets which are not yet backported. The main reason to use a SEQPACKET socket is so that the slirp helper is reliably notified when the other end hangs up. Rather than backporting the upstream improvements, switch to a DGRAM socket and use an extra control pipe to find out when the parent bhyve process has exited. No data is written to the pipe, we just use it to poll for POLLHUP. This commit can be reverted once CheriBSD has been synced up to commit 69f61ce or later.
1 parent cf1a4f8 commit 3aaf276

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

usr.sbin/bhyve/net_backend_slirp.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#define SLIRP_MTU 2048
6969

7070
struct slirp_priv {
71+
int p;
7172
int s;
7273
pid_t helper;
7374
struct mevent *mevp;
@@ -84,14 +85,19 @@ slirp_init(struct net_backend *be, const char *devname __unused,
8485
posix_spawn_file_actions_t fa;
8586
pid_t child;
8687
const char **argv;
87-
char sockname[32];
88-
int error, s[2];
88+
char pipename[32], sockname[32];
89+
int error, p[2], s[2];
8990

90-
if (socketpair(PF_LOCAL, SOCK_SEQPACKET | SOCK_NONBLOCK, 0, s) != 0) {
91+
if (socketpair(PF_LOCAL, SOCK_DGRAM | SOCK_NONBLOCK, 0, s) != 0) {
9192
EPRINTLN("socketpair");
9293
return (-1);
9394
}
9495

96+
if (pipe(p) != 0) {
97+
EPRINTLN("pipe");
98+
goto err;
99+
}
100+
95101
/*
96102
* The child will exit once its connection goes away, so make sure only
97103
* one end is inherited by the child.
@@ -107,8 +113,10 @@ slirp_init(struct net_backend *be, const char *devname __unused,
107113
}
108114

109115
(void)snprintf(sockname, sizeof(sockname), "%d", s[1]);
116+
(void)snprintf(pipename, sizeof(pipename), "%d", p[1]);
110117
argv = (const char *[]){
111-
"/usr/libexec/bhyve-slirp-helper", "-S", sockname, NULL
118+
"/usr/libexec/bhyve-slirp-helper", "-S", sockname, "-P", pipename,
119+
NULL
112120
};
113121
error = posix_spawn(&child, "/usr/libexec/bhyve-slirp-helper",
114122
&fa, NULL, __DECONST(char **, argv), environ);
@@ -140,12 +148,16 @@ slirp_init(struct net_backend *be, const char *devname __unused,
140148
}
141149

142150
priv->helper = child;
151+
priv->p = p[0];
152+
(void)close(p[1]);
143153
priv->s = s[0];
144154
(void)close(s[1]);
145155

146156
return (0);
147157

148158
err:
159+
(void)close(p[0]);
160+
(void)close(p[1]);
149161
(void)close(s[0]);
150162
(void)close(s[1]);
151163
return (-1);

usr.sbin/bhyve/slirp/slirp-helper.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
struct slirp_priv {
4444
Slirp *slirp; /* libslirp handle */
4545
int sock; /* data and control socket */
46+
int pipe; /* used to signal termination */
4647
int wakeup[2]; /* used to wake up the pollfd thread */
4748
struct pollfd *pollfds;
4849
size_t npollfds;
@@ -240,7 +241,7 @@ slirp_pollfd_loop(struct slirp_priv *priv)
240241
int error;
241242

242243
for (;;) {
243-
int input, wakeup;
244+
int control, input, wakeup;
244245

245246
for (size_t i = 0; i < priv->npollfds; i++)
246247
priv->pollfds[i].fd = -1;
@@ -250,6 +251,8 @@ slirp_pollfd_loop(struct slirp_priv *priv)
250251
wakeup = slirp_addpoll(priv, priv->wakeup[0], POLLIN);
251252
/* Register for input from our parent process. */
252253
input = slirp_addpoll(priv, priv->sock, POLLIN | POLLRDHUP);
254+
/* Make sure we get woken up if the parent exits. */
255+
control = slirp_addpoll(priv, priv->pipe, POLLIN | POLLHUP);
253256

254257
timeout = UINT32_MAX;
255258
slirp_pollfds_fill_p(priv->slirp, &timeout, slirp_addpoll_cb,
@@ -283,7 +286,8 @@ slirp_pollfd_loop(struct slirp_priv *priv)
283286
* If new packets arrived from our parent, feed them to
284287
* libslirp.
285288
*/
286-
if ((pollfds[input].revents & (POLLHUP | POLLRDHUP)) != 0)
289+
if ((pollfds[input].revents & (POLLHUP | POLLRDHUP)) != 0 ||
290+
(pollfds[control].revents & POLLHUP) != 0)
287291
errx(1, "parent process closed connection");
288292
if ((pollfds[input].revents & POLLIN) != 0) {
289293
ssize_t n;
@@ -462,12 +466,17 @@ main(int argc, char **argv)
462466
Slirp *slirp;
463467
nvlist_t *config;
464468
const char *hostfwd, *vmname;
465-
int ch, fd, sd;
469+
int ch, fd, pipe, sd;
466470
bool restricted;
467471

468472
sd = -1;
469-
while ((ch = getopt(argc, argv, "S:")) != -1) {
473+
while ((ch = getopt(argc, argv, "P:S:")) != -1) {
470474
switch (ch) {
475+
case 'P':
476+
pipe = atoi(optarg);
477+
if (fcntl(pipe, F_GETFD) == -1)
478+
err(1, "invalid pipe %s", optarg);
479+
break;
471480
case 'S':
472481
sd = atoi(optarg);
473482
if (fcntl(sd, F_GETFD) == -1)
@@ -498,11 +507,15 @@ main(int argc, char **argv)
498507
err(1, "dup2(stderr)");
499508
if (dup2(sd, 3) == -1)
500509
err(1, "dup2(slirp socket)");
510+
if (dup2(pipe, 4) == -1)
511+
err(1, "dup2(control pipe)");
501512
sd = 3;
502-
closefrom(sd + 1);
513+
pipe = 4;
514+
closefrom(pipe + 1);
503515

504516
memset(&priv, 0, sizeof(priv));
505517
priv.sock = sd;
518+
priv.pipe = pipe;
506519
if (pipe2(priv.wakeup, O_CLOEXEC | O_NONBLOCK) != 0)
507520
err(1, "pipe2");
508521

0 commit comments

Comments
 (0)