diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2016-10-12 19:07:43 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2016-10-12 19:07:43 +0000 |
commit | 2c8b4a5d06668df9dd4ca308364599ed7bd90ce6 (patch) | |
tree | 1957e11b32cbb7f59e980e7bed52f779522b2dc9 /usr.sbin/switchd | |
parent | 9a8144695bfe9da05620d6691336173b6178623c (diff) |
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')
-rw-r--r-- | usr.sbin/switchd/control.c | 6 | ||||
-rw-r--r-- | usr.sbin/switchd/ofcconn.c | 42 | ||||
-rw-r--r-- | usr.sbin/switchd/ofp.c | 33 | ||||
-rw-r--r-- | usr.sbin/switchd/ofrelay.c | 4 | ||||
-rw-r--r-- | usr.sbin/switchd/parse.y | 77 | ||||
-rw-r--r-- | usr.sbin/switchd/switchd.c | 246 | ||||
-rw-r--r-- | usr.sbin/switchd/switchd.h | 28 | ||||
-rw-r--r-- | usr.sbin/switchd/types.h | 9 |
8 files changed, 278 insertions, 167 deletions
diff --git a/usr.sbin/switchd/control.c b/usr.sbin/switchd/control.c index 291e060bce6..b1b23d3ca48 100644 --- a/usr.sbin/switchd/control.c +++ b/usr.sbin/switchd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.4 2016/09/14 13:46:51 rzalamena Exp $ */ +/* $OpenBSD: control.c,v 1.5 2016/10/12 19:07:42 reyk Exp $ */ /* * Copyright (c) 2010-2016 Reyk Floeter <reyk@openbsd.org> @@ -340,8 +340,8 @@ control_dispatch_imsg(int fd, short event, void *arg) proc_compose(&env->sc_ps, PROC_OFP, imsg.hdr.type, &fd, sizeof(fd)); break; - case IMSG_CTL_DEVICE_CONNECT: - case IMSG_CTL_DEVICE_DISCONNECT: + case IMSG_CTL_CONNECT: + case IMSG_CTL_DISCONNECT: proc_compose(&env->sc_ps, PROC_PARENT, imsg.hdr.type, imsg.data, IMSG_DATA_SIZE(&imsg)); break; diff --git a/usr.sbin/switchd/ofcconn.c b/usr.sbin/switchd/ofcconn.c index a26159b47dd..059f2f4fdd9 100644 --- a/usr.sbin/switchd/ofcconn.c +++ b/usr.sbin/switchd/ofcconn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofcconn.c,v 1.11 2016/09/30 12:48:27 reyk Exp $ */ +/* $OpenBSD: ofcconn.c,v 1.12 2016/10/12 19:07:42 reyk Exp $ */ /* * Copyright (c) 2016 YASUOKA Masahiko <yasuoka@openbsd.org> @@ -20,6 +20,7 @@ #include <sys/queue.h> #include <sys/uio.h> #include <sys/socket.h> +#include <sys/un.h> #include <net/ofp.h> @@ -78,7 +79,7 @@ void ofsw_on_io(int, short, void *); int ofsw_write(struct ofsw *, struct ofcconn *); int ofsw_ofc_write_ready(struct ofsw *); void ofsw_reset_event_handlers(struct ofsw *); -int ofsw_new_ofcconn(struct ofsw *, struct switch_controller *); +int ofsw_new_ofcconn(struct ofsw *, struct switch_address *); int ofcconn_connect(struct ofcconn *); void ofcconn_on_sockio(int, short, void *); void ofcconn_connect_again(struct ofcconn *); @@ -126,30 +127,33 @@ int ofcconn_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) { struct ofsw *os; - struct switch_device *sdv; - struct switch_controller *swc; + struct switch_client swc; + struct sockaddr_un *un; switch (imsg->hdr.type) { - case IMSG_CTL_DEVICE_CONNECT: - if (IMSG_DATA_SIZE(imsg) < sizeof(*sdv)) { - log_warnx("%s: IMSG_CTL_DEVICE_CONNECT: " + case IMSG_CTL_CONNECT: + if (IMSG_DATA_SIZE(imsg) < sizeof(swc)) { + log_warnx("%s: IMSG_CTL_CONNECT: " "invalid message size", __func__); return (0); } - sdv = imsg->data; - swc = &sdv->sdv_swc; - if ((os = ofsw_create(sdv->sdv_device, imsg->fd)) != NULL) - ofsw_new_ofcconn(os, swc); + memcpy(&swc, imsg->data, sizeof(swc)); + un = (struct sockaddr_un *)&swc.swc_addr.swa_addr; + + if ((os = ofsw_create(un->sun_path, imsg->fd)) != NULL) + ofsw_new_ofcconn(os, &swc.swc_target); return (0); - case IMSG_CTL_DEVICE_DISCONNECT: - if (IMSG_DATA_SIZE(imsg) < sizeof(*sdv)) { + case IMSG_CTL_DISCONNECT: + if (IMSG_DATA_SIZE(imsg) < sizeof(swc)) { log_warnx("%s: IMSG_CTL_DEVICE_DISCONNECT: " "invalid message size", __func__); return (0); } - sdv = imsg->data; + memcpy(&swc, imsg->data, sizeof(swc)); + un = (struct sockaddr_un *)&swc.swc_addr.swa_addr; + TAILQ_FOREACH(os, &ofsw_list, os_next) { - if (!strcmp(os->os_name, sdv->sdv_device)) + if (!strcmp(os->os_name, un->sun_path)) break; } if (os) { @@ -375,7 +379,7 @@ ofsw_reset_event_handlers(struct ofsw *os) } int -ofsw_new_ofcconn(struct ofsw *os, struct switch_controller *swc) +ofsw_new_ofcconn(struct ofsw *os, struct switch_address *swa) { struct ofcconn *oc = NULL; char buf[128]; @@ -386,7 +390,7 @@ ofsw_new_ofcconn(struct ofsw *os, struct switch_controller *swc) } if (asprintf(&oc->oc_name, "tcp:%s", - print_host(&swc->swc_addr, buf, sizeof(buf))) == -1) { + print_host(&swa->swa_addr, buf, sizeof(buf))) == -1) { log_warn("%s: strdup failed", __func__); goto fail; } @@ -396,7 +400,7 @@ ofsw_new_ofcconn(struct ofsw *os, struct switch_controller *swc) } oc->oc_sw = os; oc->oc_sock = -1; - memcpy(&oc->oc_peer, &swc->swc_addr, sizeof(oc->oc_peer)); + memcpy(&oc->oc_peer, &swa->swa_addr, sizeof(oc->oc_peer)); if (ntohs(((struct sockaddr_in *)&oc->oc_peer)->sin_port) == 0) ((struct sockaddr_in *)&oc->oc_peer)->sin_port = @@ -444,7 +448,7 @@ ofcconn_connect(struct ofcconn *oc) ofcconn_on_sockio, oc); event_add(&oc->oc_evsock, NULL); - tv.tv_sec = SWITCHD_OFCCONN_TIMEOUT; + tv.tv_sec = SWITCHD_CONNECT_TIMEOUT; tv.tv_usec = 0; event_add(&oc->oc_evtimer, &tv); diff --git a/usr.sbin/switchd/ofp.c b/usr.sbin/switchd/ofp.c index 76585a72a87..5c77deeef9f 100644 --- a/usr.sbin/switchd/ofp.c +++ b/usr.sbin/switchd/ofp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofp.c,v 1.13 2016/10/05 16:40:55 reyk Exp $ */ +/* $OpenBSD: ofp.c,v 1.14 2016/10/12 19:07:42 reyk Exp $ */ /* * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org> @@ -93,8 +93,7 @@ ofp_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) { struct privsep *ps = p->p_ps; struct switchd *sc = ps->ps_env; - struct sockaddr_un un; - struct switch_device *sdv; + struct switch_client swc; struct switch_connection *con; switch (imsg->hdr.type) { @@ -103,24 +102,16 @@ ofp_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) close(sc->sc_tap); sc->sc_tap = imsg->fd; return (0); - case IMSG_CTL_DEVICE_CONNECT: - case IMSG_CTL_DEVICE_DISCONNECT: - IMSG_SIZE_CHECK(imsg, sdv); - sdv = imsg->data; - - if (strlcpy(un.sun_path, sdv->sdv_device, - sizeof(un.sun_path)) >= sizeof(un.sun_path)) { - log_warnx("invalid device: %s", sdv->sdv_device); - return (0); - } - un.sun_family = AF_UNIX; - un.sun_len = sizeof(un); - - if (imsg->hdr.type == IMSG_CTL_DEVICE_CONNECT) - ofrelay_attach(&sc->sc_server, - imsg->fd, (struct sockaddr *)&un); - else if ((con = - switchd_connbyaddr(sc, (struct sockaddr *)&un)) != NULL) + case IMSG_CTL_CONNECT: + case IMSG_CTL_DISCONNECT: + IMSG_SIZE_CHECK(imsg, &swc); + memcpy(&swc, imsg->data, sizeof(swc)); + + if (imsg->hdr.type == IMSG_CTL_CONNECT) + ofrelay_attach(&sc->sc_server, imsg->fd, + (struct sockaddr *)&swc.swc_addr.swa_addr); + else if ((con = switchd_connbyaddr(sc, + (struct sockaddr *)&swc.swc_addr.swa_addr)) != NULL) ofp_close(con); return (0); default: diff --git a/usr.sbin/switchd/ofrelay.c b/usr.sbin/switchd/ofrelay.c index 381b3c648aa..0a29941f40b 100644 --- a/usr.sbin/switchd/ofrelay.c +++ b/usr.sbin/switchd/ofrelay.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofrelay.c,v 1.5 2016/10/07 08:31:08 rzalamena Exp $ */ +/* $OpenBSD: ofrelay.c,v 1.6 2016/10/12 19:07:42 reyk Exp $ */ /* * Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org> @@ -76,7 +76,7 @@ ofrelay_run(struct privsep *ps, struct privsep_proc *p, void *arg) struct switch_server *srv = &sc->sc_server; TAILQ_INIT(&sc->sc_conns); - TAILQ_INIT(&sc->sc_devs); + TAILQ_INIT(&sc->sc_clients); srv->srv_sc = sc; event_set(&srv->srv_ev, srv->srv_fd, EV_READ, ofrelay_accept, srv); diff --git a/usr.sbin/switchd/parse.y b/usr.sbin/switchd/parse.y index a1c338f2c1c..8f051d7a8bb 100644 --- a/usr.sbin/switchd/parse.y +++ b/usr.sbin/switchd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.2 2016/09/30 11:57:57 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.3 2016/10/12 19:07:42 reyk Exp $ */ /* * Copyright (c) 2007-2016 Reyk Floeter <reyk@openbsd.org> @@ -26,6 +26,7 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/stat.h> +#include <sys/un.h> #include <ctype.h> #include <err.h> @@ -79,7 +80,7 @@ typedef struct { int64_t number; char *string; in_port_t port; - struct switch_device + struct switch_client *conn; } v; int lineno; @@ -157,51 +158,73 @@ opttls : /* empty */ { $$ = 0; } ; device : DEVICE STRING optofcconn { - struct switch_device *c; + struct switch_client *c; + struct switch_address s; + struct sockaddr_un *un; - TAILQ_FOREACH(c, &conf->sc_devs, sdv_next) { - if (strcmp(c->sdv_device, $2) == 0) + memset(&s, 0, sizeof(s)); + un = (struct sockaddr_un *)&s.swa_addr; + + if (*$2 != '/') { + yyerror("not an absolute path: %s", $2); + free($2); + YYERROR; + } + + un->sun_family = AF_LOCAL; + un->sun_len = sizeof(*un); + if (strlcpy(un->sun_path, $2, + sizeof(un->sun_path)) >= sizeof(un->sun_path)) { + yyerror("device name is too long: %s", $2); + free($2); + YYERROR; + } + free($2); + + TAILQ_FOREACH(c, &conf->sc_clients, swc_next) { + if (sockaddr_cmp((struct sockaddr *) + &c->swc_addr.swa_addr, + (struct sockaddr *)&s.swa_addr, -1) == 0) break; } if (c != NULL) { yyerror("device name is duplicated"); YYERROR; } - if (strlcpy($3->sdv_device, $2, sizeof($3->sdv_device)) - >= sizeof($3->sdv_device)) { - yyerror("device name is too long"); - YYERROR; - } - free($2); - TAILQ_INSERT_TAIL(&conf->sc_devs, $3, sdv_next); + + memcpy(&$3->swc_addr, &s, sizeof(s)); + + TAILQ_INSERT_TAIL(&conf->sc_clients, $3, swc_next); } ; optofcconn : /* empty */ { if (($$ = calloc(1, - sizeof(struct switch_device))) == NULL) + sizeof(struct switch_client))) == NULL) fatal("calloc"); - $$->sdv_swc.swc_type = SWITCH_CONN_LOCAL; + $$->swc_addr.swa_type = $$->swc_target.swa_type = + SWITCH_CONN_LOCAL; } | FORWARD TO STRING { + size_t len; + if (($$ = calloc(1, - sizeof(struct switch_device))) == NULL) + sizeof(struct switch_client))) == NULL) fatal("calloc"); - if (strncmp($3, "tcp:", 4) == 0) - $$->sdv_swc.swc_type = SWITCH_CONN_TCP; - else if (strncmp($3, "tls:", 4) == 0) - $$->sdv_swc.swc_type = SWITCH_CONN_TLS; + len = 4; + if (strncmp($3, "tcp:", len) == 0) + $$->swc_target.swa_type = SWITCH_CONN_TCP; + else if (strncmp($3, "tls:", len) == 0) + $$->swc_target.swa_type = SWITCH_CONN_TLS; else { - yyerror("foward to proto is not supported"); - free($$); - free($3); - YYERROR; + len = 0; + $$->swc_target.swa_type = SWITCH_CONN_TCP; } - if (parsehostport($3 + 4, - (struct sockaddr *)&$$->sdv_swc.swc_addr, - sizeof($$->sdv_swc.swc_addr)) == -1) { + if (parsehostport($3 + len, + (struct sockaddr *)&$$->swc_target.swa_addr, + sizeof($$->swc_target.swa_addr)) == -1) { yyerror("could not parse host and port part " - "of connect-to"); + "of forward target"); free($$); free($3); YYERROR; 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); } diff --git a/usr.sbin/switchd/switchd.h b/usr.sbin/switchd/switchd.h index 92a7533a4ad..ad94ee56306 100644 --- a/usr.sbin/switchd/switchd.h +++ b/usr.sbin/switchd/switchd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: switchd.h,v 1.15 2016/10/07 08:49:53 reyk Exp $ */ +/* $OpenBSD: switchd.h,v 1.16 2016/10/12 19:07:42 reyk Exp $ */ /* * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org> @@ -76,6 +76,11 @@ struct multipart_message { }; SLIST_HEAD(multipart_list, multipart_message); +struct switch_address { + enum switch_conn_type swa_type; + struct sockaddr_storage swa_addr; +}; + struct switch_connection { unsigned int con_id; unsigned int con_instance; @@ -113,18 +118,15 @@ struct switch_server { struct switchd *srv_sc; }; -struct switch_controller { - enum switch_conn_type swc_type; - struct sockaddr_storage swc_addr; -}; - -struct switch_device { - char sdv_device[PATH_MAX]; - struct switch_controller sdv_swc; - TAILQ_ENTRY(switch_device) - sdv_next; +struct switch_client { + struct switch_address swc_addr; + struct switch_address swc_target; + struct event swc_ev; + void *swc_arg; + TAILQ_ENTRY(switch_client) + swc_next; }; -TAILQ_HEAD(switch_devices, switch_device); +TAILQ_HEAD(switch_clients, switch_client); struct switchd { struct privsep sc_ps; @@ -136,7 +138,7 @@ struct switchd { unsigned int sc_cache_timeout; char sc_conffile[PATH_MAX]; uint8_t sc_opts; - struct switch_devices sc_devs; + struct switch_clients sc_clients; struct switch_connections sc_conns; }; diff --git a/usr.sbin/switchd/types.h b/usr.sbin/switchd/types.h index a8300b92bcf..b9d8b81c95b 100644 --- a/usr.sbin/switchd/types.h +++ b/usr.sbin/switchd/types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: types.h,v 1.6 2016/10/06 20:27:44 reyk Exp $ */ +/* $OpenBSD: types.h,v 1.7 2016/10/12 19:07:42 reyk Exp $ */ /* * Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org> @@ -43,8 +43,7 @@ #define SWITCHD_CACHE_MAX 4096 /* Default MAC address cache limit */ #define SWITCHD_CACHE_TIMEOUT 240 /* t/o in seconds for learned MACs */ -#define SWITCHD_OFCCONN_TIMEOUT 20 /* connect timeout for OpenFlow ch. */ - +#define SWITCHD_CONNECT_TIMEOUT 5 #ifndef ETHER_ADDR_LEN #define ETHER_ADDR_LEN 6 @@ -69,8 +68,8 @@ enum imsg_type { IMSG_CTL_SWITCH, IMSG_CTL_MAC, IMSG_CTL_SHOW_SUM, - IMSG_CTL_DEVICE_CONNECT, - IMSG_CTL_DEVICE_DISCONNECT, + IMSG_CTL_CONNECT, + IMSG_CTL_DISCONNECT, IMSG_TAPFD }; |