summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2016-10-12 19:07:43 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2016-10-12 19:07:43 +0000
commit2c8b4a5d06668df9dd4ca308364599ed7bd90ce6 (patch)
tree1957e11b32cbb7f59e980e7bed52f779522b2dc9 /usr.sbin
parent9a8144695bfe9da05620d6691336173b6178623c (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')
-rw-r--r--usr.sbin/switchctl/parser.c104
-rw-r--r--usr.sbin/switchctl/parser.h25
-rw-r--r--usr.sbin/switchctl/switchctl.822
-rw-r--r--usr.sbin/switchctl/switchctl.c63
-rw-r--r--usr.sbin/switchd/control.c6
-rw-r--r--usr.sbin/switchd/ofcconn.c42
-rw-r--r--usr.sbin/switchd/ofp.c33
-rw-r--r--usr.sbin/switchd/ofrelay.c4
-rw-r--r--usr.sbin/switchd/parse.y77
-rw-r--r--usr.sbin/switchd/switchd.c246
-rw-r--r--usr.sbin/switchd/switchd.h28
-rw-r--r--usr.sbin/switchd/types.h9
12 files changed, 405 insertions, 254 deletions
diff --git a/usr.sbin/switchctl/parser.c b/usr.sbin/switchctl/parser.c
index 2ec8153b0b6..39fa77414d0 100644
--- a/usr.sbin/switchctl/parser.c
+++ b/usr.sbin/switchctl/parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: parser.c,v 1.2 2016/07/19 18:09:39 reyk Exp $ */
+/* $OpenBSD: parser.c,v 1.3 2016/10/12 19:07:42 reyk Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -22,6 +22,7 @@
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/tree.h>
+#include <sys/un.h>
#include <err.h>
#include <errno.h>
@@ -41,8 +42,6 @@ enum token_type {
KEYWORD,
PATH,
ADDRESS,
- FQDN,
- DEVICE,
URI
};
@@ -58,14 +57,14 @@ static const struct token t_reset[];
static const struct token t_log[];
static const struct token t_load[];
static const struct token t_show[];
-static const struct token t_device[];
-static const struct token t_device_add[];
-static const struct token t_device_remove[];
-static const struct token t_connect_to[];
+static const struct token t_connect[];
+static const struct token t_disconnect[];
+static const struct token t_forward_to[];
static const struct token t_uri[];
static const struct token t_main[] = {
- { KEYWORD, "device", NONE, t_device },
+ { KEYWORD, "connect", CONNECT, t_connect },
+ { KEYWORD, "disconnect", DISCONNECT, t_disconnect },
{ KEYWORD, "load", LOAD, t_load },
{ KEYWORD, "log", NONE, t_log },
{ KEYWORD, "monitor", MONITOR, NULL },
@@ -97,21 +96,17 @@ static const struct token t_show[] = {
{ KEYWORD, "macs", SHOW_MACS, NULL },
{ ENDTOKEN, "", NONE, NULL }
};
-static const struct token t_device[] = {
- { KEYWORD, "add", ADD_DEVICE, t_device_add },
- { KEYWORD, "remove", REMOVE_DEVICE, t_device_remove },
+static const struct token t_connect[] = {
+ { ADDRESS, "", NONE, t_forward_to },
{ ENDTOKEN, "", NONE, NULL }
};
-static const struct token t_device_add[] = {
- { DEVICE, "", NONE, t_connect_to },
+static const struct token t_disconnect[] = {
+ { ADDRESS, "", NONE, NULL },
{ ENDTOKEN, "", NONE, NULL }
};
-static const struct token t_device_remove[] = {
- { DEVICE, "", NONE, NULL },
- { ENDTOKEN, "", NONE, NULL }
-};
-static const struct token t_connect_to[] = {
- { KEYWORD, "connect-to", NONE, t_uri },
+static const struct token t_forward_to[] = {
+ { NOTOKEN, "", NONE, NULL },
+ { KEYWORD, "forward-to", NONE, t_uri },
{ ENDTOKEN, "", NONE, NULL }
};
static const struct token t_uri[] = {
@@ -123,7 +118,8 @@ static struct parse_result res;
const struct token *match_token(char *, const struct token []);
void show_valid_args(const struct token []);
-int parse_addr(const char *);
+int parse_addr(const char *,
+ struct sockaddr_storage *);
struct parse_result *
parse(int argc, char *argv[])
@@ -158,19 +154,60 @@ parse(int argc, char *argv[])
}
int
-parse_addr(const char *word)
+parse_addr(const char *word, struct sockaddr_storage *ss)
{
- struct addrinfo hints, *r;
+ struct addrinfo hints, *ai;
+ struct sockaddr_un *un;
+
+ memset(ss, 0, sizeof(*ss));
+
+ /* device */
+ if (*word == '/') {
+ un = (struct sockaddr_un *)ss;
+ if (strlcpy(un->sun_path, word, sizeof(un->sun_path)) >=
+ sizeof(un->sun_path)) {
+ warnx("invalid path");
+ return (-1);
+ }
+ un->sun_family = AF_LOCAL;
+ un->sun_len = sizeof(*un);
+ return (0);
+ }
- bzero(&hints, sizeof(hints));
+ /* address */
+ memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM; /* dummy */
hints.ai_family = PF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST;
- if (getaddrinfo(word, "0", &hints, &r) == 0) {
+ if (getaddrinfo(word, "0", &hints, &ai) == 0) {
+ if (ai->ai_addrlen > sizeof(*ss)) {
+ warnx("invalid address length");
+ return (-1);
+ }
+ memcpy(ss, ai->ai_addr, ai->ai_addrlen);
+ ss->ss_len = ai->ai_addrlen;
+ freeaddrinfo(ai);
+ return (0);
+ }
+
+ /* FQDN */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_DGRAM; /* dummy */
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_ADDRCONFIG;
+ if (getaddrinfo(word, "0", &hints, &ai) == 0) {
+ /* Pick first name only */
+ if (ai->ai_addrlen > sizeof(*ss)) {
+ warnx("invalid address length");
+ return (-1);
+ }
+ memcpy(ss, ai->ai_addr, ai->ai_addrlen);
+ ss->ss_len = ai->ai_addrlen;
+ freeaddrinfo(ai);
return (0);
}
- return (1);
+ return (-1);
}
@@ -197,7 +234,6 @@ match_token(char *word, const struct token table[])
res.action = t->value;
}
break;
- case DEVICE:
case PATH:
if (!match && word != NULL && strlen(word) > 0) {
res.path = strdup(word);
@@ -206,14 +242,8 @@ match_token(char *word, const struct token table[])
}
break;
case ADDRESS:
- case FQDN:
if (!match && word != NULL && strlen(word) > 0) {
- parse_addr(word);
- res.host = strdup(word);
- if (parse_addr(word) == 0)
- res.htype = HOST_IPADDR;
- else
- res.htype = HOST_FQDN;
+ parse_addr(word, &res.addr);
match++;
t = &table[i];
}
@@ -260,13 +290,7 @@ show_valid_args(const struct token table[])
fprintf(stderr, " <path>\n");
break;
case ADDRESS:
- fprintf(stderr, " <ipaddr>\n");
- break;
- case FQDN:
- fprintf(stderr, " <fqdn>\n");
- break;
- case DEVICE:
- fprintf(stderr, " <device>\n");
+ fprintf(stderr, " <address>\n");
break;
case URI:
fprintf(stderr, " <uri>\n");
diff --git a/usr.sbin/switchctl/parser.h b/usr.sbin/switchctl/parser.h
index 8b885886b8e..07cfe350fd0 100644
--- a/usr.sbin/switchctl/parser.h
+++ b/usr.sbin/switchctl/parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: parser.h,v 1.1 2016/07/19 16:54:26 reyk Exp $ */
+/* $OpenBSD: parser.h,v 1.2 2016/10/12 19:07:42 reyk Exp $ */
/*
* Copyright (c) 2007-2015 Reyk Floeter <reyk@openbsd.org>
@@ -30,21 +30,20 @@ enum actions {
LOG_VERBOSE,
LOG_BRIEF,
RESETALL,
- ADD_DEVICE,
- REMOVE_DEVICE
+ CONNECT,
+ DISCONNECT
};
struct parse_result {
- enum actions action;
- struct imsgbuf *ibuf;
- char *path;
- char *caname;
- char *pass;
- char *host;
- char *peer;
- char *uri;
- int htype;
- int quiet;
+ enum actions action;
+ struct imsgbuf *ibuf;
+ char *path;
+ char *caname;
+ char *pass;
+ char *peer;
+ char *uri;
+ struct sockaddr_storage addr;
+ int quiet;
};
#define HOST_IPADDR 1
diff --git a/usr.sbin/switchctl/switchctl.8 b/usr.sbin/switchctl/switchctl.8
index d4c1ecefa35..e9543ba1d2f 100644
--- a/usr.sbin/switchctl/switchctl.8
+++ b/usr.sbin/switchctl/switchctl.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: switchctl.8,v 1.1 2016/07/19 16:54:26 reyk Exp $
+.\" $OpenBSD: switchctl.8,v 1.2 2016/10/12 19:07:42 reyk Exp $
.\"
.\" Copyright (c) 2007-2015 Reyk Floeter <reyk@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 19 2016 $
+.Dd $Mdocdate: October 12 2016 $
.Dt SWITCHCTL 8
.Os
.Sh NAME
@@ -49,11 +49,25 @@ to communicate with
The following commands are available to control
.Xr switchd 8 :
.Bl -tag -width Ds
-.It Cm device add Ar filename
-Add new
+.It Cm connect Ar address Op Cm forward-to Ar address
+Connect to a new switch by
+.Ar address ,
+for example
+.Ar 10.1.1.1 ,
+or a
.Xr switch 4
control device, for example
.Pa /dev/switch0 .
+.Nm switchd
+will forward all OpenFlow requests of the switch to a remote controller
+if the optional
+.Cm forward-to
+.Ar address
+is specified.
+.It Cm disconnect Ar address
+Close the client connection to a remote switch or a
+.Xr switch 4
+control device.
.It Cm load Ar filename
Reload the configuration from the specified file.
.It Cm log brief
diff --git a/usr.sbin/switchctl/switchctl.c b/usr.sbin/switchctl/switchctl.c
index 6ecc015e8e7..ed73eaea210 100644
--- a/usr.sbin/switchctl/switchctl.c
+++ b/usr.sbin/switchctl/switchctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: switchctl.c,v 1.3 2016/09/28 09:13:30 reyk Exp $ */
+/* $OpenBSD: switchctl.c,v 1.4 2016/10/12 19:07:42 reyk Exp $ */
/*
* Copyright (c) 2007-2015 Reyk Floeter <reyk@openbsd.org>
@@ -83,8 +83,8 @@ main(int argc, char *argv[])
struct sockaddr_un sun;
struct parse_result *res;
struct imsg imsg;
- struct switch_device sdv;
- struct switch_controller *swc;
+ struct switch_client swc;
+ struct switch_address *to;
int ctl_sock;
int done = 1;
int n;
@@ -92,6 +92,7 @@ main(int argc, char *argv[])
int v = 0;
int quiet = 0;
const char *sock = SWITCHD_SOCKET;
+ size_t len;
while ((ch = getopt(argc, argv, "qs:")) != -1) {
switch (ch) {
@@ -186,40 +187,42 @@ main(int argc, char *argv[])
"Switch", "Port", "Type", "Name", "Info");
done = 0;
break;
- case ADD_DEVICE:
- case REMOVE_DEVICE:
- memset(&sdv, 0, sizeof(sdv));
- swc = &sdv.sdv_swc;
- if (res->path[0] != '/')
- strlcpy(sdv.sdv_device, "/dev/",
- sizeof(sdv.sdv_device));
- if (strlcat(sdv.sdv_device, res->path,
- sizeof(sdv.sdv_device)) >= sizeof(sdv.sdv_device))
- errx(1, "path is too long");
- if (res->action == REMOVE_DEVICE) {
- imsg_compose(ibuf, IMSG_CTL_DEVICE_DISCONNECT, 0, 0, -1,
- &sdv, sizeof(sdv));
+ case CONNECT:
+ case DISCONNECT:
+ memset(&swc, 0, sizeof(swc));
+ if (res->addr.ss_family == AF_UNSPEC)
+ errx(1, "invalid address");
+
+ memcpy(&swc.swc_addr.swa_addr, &res->addr, sizeof(res->addr));
+ if (res->action == DISCONNECT) {
+ imsg_compose(ibuf, IMSG_CTL_DISCONNECT, 0, 0, -1,
+ &swc, sizeof(swc));
break;
}
+
+ to = &swc.swc_target;
if (res->uri == NULL || res->uri[0] == '\0')
- swc->swc_type = SWITCH_CONN_LOCAL;
+ to->swa_type = SWITCH_CONN_LOCAL;
else {
- if (strncmp(res->uri, "tcp:", 4) == 0)
- swc->swc_type = SWITCH_CONN_TCP;
- else if (strncmp(res->uri, "tls:", 4) == 0)
- swc->swc_type = SWITCH_CONN_TLS;
- else
- errx(1, "protocol field is unknown");
-
- if (parsehostport(res->uri + 4,
- (struct sockaddr *)&swc->swc_addr,
- sizeof(swc->swc_addr)) != 0)
+ len = 4;
+ if (strncmp(res->uri, "tcp:", len) == 0)
+ to->swa_type = SWITCH_CONN_TCP;
+ else if (strncmp(res->uri, "tls:", len) == 0)
+ to->swa_type = SWITCH_CONN_TLS;
+ else {
+ /* set the default */
+ to->swa_type = SWITCH_CONN_TCP;
+ len = 0;
+ }
+
+ if (parsehostport(res->uri + len,
+ (struct sockaddr *)&to->swa_addr,
+ sizeof(to->swa_addr)) != 0)
errx(1,
"couldn't parse name-or-address and port");
- warnx("%s", sdv.sdv_device);
}
- imsg_compose(ibuf, IMSG_CTL_DEVICE_CONNECT, 0, 0, -1,
- &sdv, sizeof(sdv));
+ imsg_compose(ibuf, IMSG_CTL_CONNECT, 0, 0, -1,
+ &swc, sizeof(swc));
break;
case RESETALL:
imsg_compose(ibuf, IMSG_CTL_RESET, 0, 0, -1, &v, sizeof(v));
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
};