summaryrefslogtreecommitdiffstats
path: root/usr.sbin/switchd/switchd.c
diff options
context:
space:
mode:
authorreyk <reyk@openbsd.org>2016-10-12 19:07:42 +0000
committerreyk <reyk@openbsd.org>2016-10-12 19:07:42 +0000
commit60874843d5beb38ccd258f1fab55dddb4dff5fd5 (patch)
treed774bb00fe0a9f5d6274709946bbf1d7856e6ec2 /usr.sbin/switchd/switchd.c
parentCompare to see if pane status line has actually changed, not just size, and (diff)
downloadwireguard-openbsd-60874843d5beb38ccd258f1fab55dddb4dff5fd5.tar.xz
wireguard-openbsd-60874843d5beb38ccd258f1fab55dddb4dff5fd5.zip
Start reworking the "device" support in switchd: Once connected, a
device is just an fd that is connected to a switch, either via TCP or via /dev/switch. Change the switchctl from "device add" to "connect" etc. This change is an intermediate step towards other changes, including the configuration grammar, so a few things will be left undocumented for now. switchctl(8) examples, switchctl connect /dev/switch0 switchctl connect /dev/switch0 forward-to 10.1.1.1 switchctl connect 127.0.0.1 switchctl connect 127.0.0.1 forward-to 10.1.1.1 switchctl disconnect /dev/switch0 Discussed with rzalamena@
Diffstat (limited to 'usr.sbin/switchd/switchd.c')
-rw-r--r--usr.sbin/switchd/switchd.c246
1 files changed, 169 insertions, 77 deletions
diff --git a/usr.sbin/switchd/switchd.c b/usr.sbin/switchd/switchd.c
index 72e62fb35da..64b26fbf452 100644
--- a/usr.sbin/switchd/switchd.c
+++ b/usr.sbin/switchd/switchd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: switchd.c,v 1.13 2016/09/30 12:32:31 reyk Exp $ */
+/* $OpenBSD: switchd.c,v 1.14 2016/10/12 19:07:42 reyk Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
+#include <sys/un.h>
#include <sys/queue.h>
#include <arpa/inet.h>
@@ -45,8 +46,9 @@ int parent_dispatch_ofp(int, struct privsep_proc *, struct imsg *);
int parent_dispatch_control(int, struct privsep_proc *, struct imsg *);
int parent_configure(struct switchd *);
int parent_reload(struct switchd *);
-void parent_device_connect(struct privsep *, struct switch_device *);
-int switch_device_cmp(struct switch_device *, struct switch_device *);
+void parent_connect(struct privsep *, struct switch_client *);
+void parent_connected(int, short, void *);
+void parent_disconnect(struct privsep *, struct switch_client *);
__dead void usage(void);
@@ -152,7 +154,7 @@ main(int argc, char *argv[])
ps = &sc->sc_ps;
ps->ps_env = sc;
TAILQ_INIT(&ps->ps_rcsocks);
- TAILQ_INIT(&sc->sc_devs);
+ TAILQ_INIT(&sc->sc_clients);
if (parse_config(sc->sc_conffile, sc) == -1) {
proc_kill(&sc->sc_ps);
@@ -362,7 +364,7 @@ parent_sig_handler(int sig, short event, void *arg)
int
parent_configure(struct switchd *sc)
{
- struct switch_device *c;
+ struct switch_client *swc, *swcn;
int fd;
if ((fd = switchd_tap()) == -1)
@@ -370,8 +372,8 @@ parent_configure(struct switchd *sc)
proc_compose_imsg(&sc->sc_ps, PROC_OFP, -1,
IMSG_TAPFD, -1, fd, NULL, 0);
- TAILQ_FOREACH(c, &sc->sc_devs, sdv_next) {
- parent_device_connect(&sc->sc_ps, c);
+ TAILQ_FOREACH_SAFE(swc, &sc->sc_clients, swc_next, swcn) {
+ parent_connect(&sc->sc_ps, swc);
}
return (0);
@@ -381,43 +383,39 @@ int
parent_reload(struct switchd *sc)
{
struct switchd newconf;
- struct switch_device *sdv, *osdv, *sdvn;
- enum privsep_procid procid;
+ struct switch_client *swc, *oswc, *swcn;
memset(&newconf, 0, sizeof(newconf));
- TAILQ_INIT(&newconf.sc_devs);
+ TAILQ_INIT(&newconf.sc_clients);
TAILQ_INIT(&newconf.sc_conns);
if (parse_config(sc->sc_conffile, &newconf) != -1) {
- TAILQ_FOREACH_SAFE(sdv, &sc->sc_devs, sdv_next, sdvn) {
- TAILQ_FOREACH(osdv, &newconf.sc_devs, sdv_next) {
- if (switch_device_cmp(osdv, sdv) == 0) {
- TAILQ_REMOVE(&newconf.sc_devs,
- osdv, sdv_next);
+ TAILQ_FOREACH_SAFE(swc, &sc->sc_clients, swc_next, swcn) {
+ TAILQ_FOREACH(oswc, &newconf.sc_clients, swc_next) {
+ if (sockaddr_cmp((struct sockaddr *)
+ &oswc->swc_addr.swa_addr,
+ (struct sockaddr *)
+ &swc->swc_addr.swa_addr, -1) == 0) {
+ TAILQ_REMOVE(&newconf.sc_clients,
+ oswc, swc_next);
break;
}
}
- if (osdv == NULL) {
+ if (oswc == NULL) {
/* Removed */
- TAILQ_REMOVE(&sc->sc_devs, sdv, sdv_next);
- procid = (sdv->sdv_swc.swc_type ==
- SWITCH_CONN_LOCAL)
- ? PROC_OFP : PROC_OFCCONN;
- proc_compose_imsg(&sc->sc_ps, procid, -1,
- IMSG_CTL_DEVICE_DISCONNECT,
- -1, -1, sdv, sizeof(*sdv));
+ parent_disconnect(&sc->sc_ps, swc);
} else {
/* Keep the existing one */
- TAILQ_REMOVE(&newconf.sc_devs, osdv, sdv_next);
- free(osdv);
+ TAILQ_REMOVE(&newconf.sc_clients,
+ oswc, swc_next);
+ free(oswc);
}
}
- TAILQ_FOREACH(sdv, &newconf.sc_devs, sdv_next) {
- procid =
- (sdv->sdv_swc.swc_type == SWITCH_CONN_LOCAL)
- ? PROC_OFP : PROC_OFCCONN;
- TAILQ_INSERT_TAIL(&sc->sc_devs, sdv, sdv_next);
- parent_device_connect(&sc->sc_ps, sdv);
+ TAILQ_FOREACH_SAFE(swc, &newconf.sc_clients, swc_next, swcn) {
+ TAILQ_REMOVE(&newconf.sc_clients, swc, swc_next);
+ TAILQ_INSERT_TAIL(&sc->sc_clients, swc, swc_next);
+
+ parent_connect(&sc->sc_ps, swc);
}
}
@@ -427,26 +425,41 @@ parent_reload(struct switchd *sc)
int
parent_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
{
+ struct switch_client *swc, *oswc;
+ struct privsep *ps = p->p_ps;
+ struct switchd *sc = ps->ps_env;
+
switch (imsg->hdr.type) {
- case IMSG_CTL_DEVICE_CONNECT:
- case IMSG_CTL_DEVICE_DISCONNECT:
- if (IMSG_DATA_SIZE(imsg) <
- sizeof(struct switch_device)) {
- log_warnx("%s: IMSG_CTL_DEVICE_CONNECT: "
- "message size is wrong", __func__);
+ case IMSG_CTL_CONNECT:
+ case IMSG_CTL_DISCONNECT:
+ IMSG_SIZE_CHECK(imsg, swc);
+
+ /* Need to allocate it in case it is reused */
+ if ((swc = calloc(1, sizeof(*swc))) == NULL) {
+ log_warnx("%s: calloc", __func__);
return (0);
}
- if (imsg->hdr.type == IMSG_CTL_DEVICE_CONNECT)
- parent_device_connect(p->p_ps, imsg->data);
- else {
- /*
- * Since we don't know which the device was attached
- * to, we send the message to the both.
- */
- proc_compose(p->p_ps, PROC_OFP,
- imsg->hdr.type, imsg->data, IMSG_DATA_SIZE(imsg));
- proc_compose(p->p_ps, PROC_OFCCONN,
- imsg->hdr.type, imsg->data, IMSG_DATA_SIZE(imsg));
+ memcpy(swc, imsg->data, sizeof(*swc));
+ memset(&swc->swc_ev, 0, sizeof(swc->swc_ev));
+
+ if (imsg->hdr.type == IMSG_CTL_CONNECT) {
+ TAILQ_INSERT_TAIL(&sc->sc_clients, swc, swc_next);
+ parent_connect(p->p_ps, swc);
+ } else {
+ TAILQ_FOREACH(oswc, &sc->sc_clients, swc_next) {
+ if (sockaddr_cmp((struct sockaddr *)
+ &oswc->swc_addr.swa_addr,
+ (struct sockaddr *)
+ &swc->swc_addr.swa_addr, -1) == 0) {
+ parent_disconnect(ps, oswc);
+ break;
+ }
+ }
+ if (oswc == NULL)
+ log_warnx("client %s is not connected",
+ print_host(&swc->swc_addr.swa_addr,
+ NULL, 0));
+ free(swc);
}
return (0);
default:
@@ -468,52 +481,131 @@ parent_shutdown(struct switchd *sc)
}
void
-parent_device_connect(struct privsep *ps, struct switch_device *sdv)
+parent_connect(struct privsep *ps, struct switch_client *swc)
{
- int fd;
+ struct switchd *sc = ps->ps_env;
+ struct sockaddr_storage *ss;
+ struct sockaddr_un *un;
+ struct sockaddr_in *sin4;
+ struct sockaddr_in6 *sin6;
+ int fd = -1;
+ struct timeval tv;
+
+ ss = &swc->swc_addr.swa_addr;
+
+ if (ss->ss_len == 0) {
+ log_warnx("%s: invalid address", __func__);
+ goto fail;
+ }
+ swc->swc_arg = ps;
+ memset(&swc->swc_ev, 0, sizeof(swc->swc_ev));
+
+ switch (ss->ss_family) {
+ case AF_LOCAL:
+ un = (struct sockaddr_un *)ss;
+
+ /* restrict the opening path to /dev/switch* */
+ if (strncmp(un->sun_path, "/dev/switch",
+ strlen("/dev/switch")) != 0) {
+ log_warnx("%s: device path is wrong: %s", __func__,
+ un->sun_path);
+ goto fail;
+ }
- /* restrict the opening path to /dev/switch* */
- if (strncmp(sdv->sdv_device, "/dev/switch", 11) != 0) {
- log_warnx("%s: device path is wrong: %s", __func__,
- sdv->sdv_device);
- goto on_error;
+ if ((fd = open(un->sun_path, O_RDWR | O_NONBLOCK)) == -1) {
+ log_warn("%s: failed to open %s",
+ __func__, un->sun_path);
+ goto fail;
+ }
+ break;
+ case AF_INET:
+ case AF_INET6:
+ if (ss->ss_family == AF_INET) {
+ sin4 = (struct sockaddr_in *)ss;
+ if (sin4->sin_port == 0)
+ sin4->sin_port = htons(SWITCHD_CTLR_PORT);
+ } else if (ss->ss_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)ss;
+ if (sin6->sin6_port == 0)
+ sin6->sin6_port = htons(SWITCHD_CTLR_PORT);
+ }
+
+ if ((fd = switchd_socket((struct sockaddr *)ss, 0)) == -1) {
+ log_debug("%s: failed to get socket for %s", __func__,
+ print_host(ss, NULL, 0));
+ goto fail;
+ }
+
+ retry:
+ if (connect(fd, (struct sockaddr *)ss, ss->ss_len) == -1) {
+ if (errno == EINTR)
+ goto retry;
+ if (errno == EINPROGRESS) {
+ tv.tv_sec = SWITCHD_CONNECT_TIMEOUT;
+ tv.tv_usec = 0;
+ event_set(&swc->swc_ev, fd, EV_WRITE|EV_TIMEOUT,
+ parent_connected, swc);
+ event_add(&swc->swc_ev, &tv);
+ return;
+ }
+
+ log_warn("%s: failed to connect to %s, fd %d", __func__,
+ print_host(ss, NULL, 0), fd);
+ goto fail;
+ }
+
+ break;
}
- if ((fd = open(sdv->sdv_device, O_RDWR | O_NONBLOCK)) == -1) {
- log_warn("%s: open(%s) failed", __func__, sdv->sdv_device);
- goto on_error;
+ parent_connected(fd, 0, swc);
+ return;
+
+ fail:
+ TAILQ_REMOVE(&sc->sc_clients, swc, swc_next);
+ free(swc);
+}
+
+void
+parent_connected(int fd, short event, void *arg)
+{
+ struct switch_client *swc = arg;
+ struct privsep *ps = swc->swc_arg;
+ struct switchd *sc = ps->ps_env;
+
+ if (event & EV_TIMEOUT) {
+ log_debug("%s: failed to connect to %s", __func__,
+ print_host(&swc->swc_addr.swa_addr, NULL, 0));
+ TAILQ_REMOVE(&sc->sc_clients, swc, swc_next);
+ free(swc);
+ return;
}
- switch (sdv->sdv_swc.swc_type) {
+ switch (swc->swc_target.swa_type) {
case SWITCH_CONN_LOCAL:
- proc_compose_imsg(ps, PROC_OFP, -1, IMSG_CTL_DEVICE_CONNECT,
- -1, fd, sdv, sizeof(*sdv));
+ proc_compose_imsg(ps, PROC_OFP, -1, IMSG_CTL_CONNECT,
+ -1, fd, swc, sizeof(*swc));
break;
case SWITCH_CONN_TLS:
case SWITCH_CONN_TCP:
- proc_compose_imsg(ps, PROC_OFCCONN, -1, IMSG_CTL_DEVICE_CONNECT,
- -1, fd, sdv, sizeof(struct switch_device));
+ proc_compose_imsg(ps, PROC_OFCCONN, -1, IMSG_CTL_CONNECT,
+ -1, fd, swc, sizeof(*swc));
break;
default:
fatalx("not implemented");
}
-on_error:
- return;
}
-int
-switch_device_cmp(struct switch_device *a,
- struct switch_device *b)
+void
+parent_disconnect(struct privsep *ps, struct switch_client *swc)
{
- struct switch_controller *ca = &a->sdv_swc;
- struct switch_controller *cb = &b->sdv_swc;
- int c;
+ struct switchd *sc = ps->ps_env;
+ enum privsep_procid target;
+
+ TAILQ_REMOVE(&sc->sc_clients, swc, swc_next);
- if ((c = strcmp(a->sdv_device, b->sdv_device)) != 0)
- return (c);
- if ((c = cb->swc_type - ca->swc_type) != 0)
- return (c);
+ target = swc->swc_target.swa_type == SWITCH_CONN_LOCAL ?
+ PROC_OFP : PROC_OFCCONN;
+ proc_compose(ps, target, IMSG_CTL_DISCONNECT, swc, sizeof(*swc));
- return (sockaddr_cmp((struct sockaddr *)&ca->swc_addr,
- (struct sockaddr *)&cb->swc_addr, -1));
+ free(swc);
}