summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrzalamena <rzalamena@openbsd.org>2016-10-07 08:31:08 +0000
committerrzalamena <rzalamena@openbsd.org>2016-10-07 08:31:08 +0000
commit9bff1a65ea3974b509e26cef5e632d9885155b69 (patch)
tree2518b44b15a760c38b5f32f4fafe54ac573d254e
parentUse detach hook to notify switch(4) about interface removals instead of (diff)
downloadwireguard-openbsd-9bff1a65ea3974b509e26cef5e632d9885155b69.tar.xz
wireguard-openbsd-9bff1a65ea3974b509e26cef5e632d9885155b69.zip
Add support for multipart replies and implement a simple ofp 1.3.5 error
message sending function. ok reyk@
-rw-r--r--usr.sbin/switchd/ofp13.c130
-rw-r--r--usr.sbin/switchd/ofrelay.c4
-rw-r--r--usr.sbin/switchd/switchd.h20
3 files changed, 143 insertions, 11 deletions
diff --git a/usr.sbin/switchd/ofp13.c b/usr.sbin/switchd/ofp13.c
index 9f78a758486..6da8bf2189b 100644
--- a/usr.sbin/switchd/ofp13.c
+++ b/usr.sbin/switchd/ofp13.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofp13.c,v 1.17 2016/09/30 12:48:27 reyk Exp $ */
+/* $OpenBSD: ofp13.c,v 1.18 2016/10/07 08:31:08 rzalamena Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -54,8 +54,6 @@ int ofp13_echo_request(struct switchd *, struct switch_connection *,
int ofp13_validate_error(struct switchd *,
struct sockaddr_storage *, struct sockaddr_storage *,
struct ofp_header *, struct ibuf *);
-int ofp13_error(struct switchd *, struct switch_connection *,
- struct ofp_header *, struct ibuf *);
int ofp13_validate_oxm_basic(struct ibuf *, off_t, int, uint8_t);
int ofp13_validate_oxm(struct switchd *, struct ofp_ox_match *,
struct ofp_header *, struct ibuf *, off_t);
@@ -92,6 +90,8 @@ int ofp13_flow_stats(struct switchd *, struct switch_connection *,
uint32_t, uint32_t, uint8_t);
int ofp13_table_features(struct switchd *, struct switch_connection *,
uint8_t);
+int ofp13_error(struct switchd *, struct switch_connection *,
+ struct ofp_header *, struct ibuf *, uint16_t, uint16_t);
struct ofp_group_mod *
ofp13_group(struct switch_connection *, struct ibuf *,
@@ -1048,20 +1048,35 @@ ofp13_multipart_reply(struct switchd *sc, struct switch_connection *con,
{
struct ofp_multipart *mp;
struct ofp_table_features *tf;
- int readlen, type;
+ int readlen, type, flags;
int remaining;
if ((mp = ibuf_getdata(ibuf, sizeof(*mp))) == NULL)
return (-1);
- if (mp->mp_flags & OFP_MP_FLAG_REPLY_MORE) {
- /* TODO support multiple fragments. */
- return (-1);
- }
-
type = ntohs(mp->mp_type);
+ flags = ntohs(mp->mp_flags);
remaining = ntohs(oh->oh_length) - sizeof(*mp);
+ if (flags & OFP_MP_FLAG_REPLY_MORE) {
+ if (ofp_multipart_add(con, oh->oh_xid, type) == -1) {
+ ofp13_error(sc, con, oh, ibuf,
+ OFP_ERRTYPE_BAD_REQUEST,
+ OFP_ERRREQ_MULTIPART_OVERFLOW);
+ ofp_multipart_del(con, oh->oh_xid);
+ return (0);
+ }
+
+ /*
+ * We don't need to concatenate with other messages,
+ * because the specification says that switches don't
+ * break objects. We should only need this if our parser
+ * requires the whole data before hand, but then we have
+ * better ways to achieve the same thing.
+ */
+ } else
+ ofp_multipart_del(con, oh->oh_xid);
+
switch (type) {
case OFP_MP_T_TABLE_FEATURES:
read_next_table:
@@ -1409,6 +1424,45 @@ ofp13_table_features(struct switchd *sc, struct switch_connection *con,
return (0);
}
+int
+ofp13_error(struct switchd *sc, struct switch_connection *con,
+ struct ofp_header *oh, struct ibuf *ibuf, uint16_t type, uint16_t code)
+{
+ struct ibuf *obuf;
+ struct ofp_error *err;
+ struct ofp_header *header;
+ int rv, dlen;
+
+ if ((obuf = ibuf_static()) == NULL ||
+ (err = ibuf_advance(obuf, sizeof(*err))) == NULL)
+ return (-1);
+
+ header = &err->err_oh;
+ err->err_type = htons(type);
+ err->err_code = htons(code);
+
+ /* Copy the first message bytes for the error payload. */
+ dlen = ibuf_size(ibuf);
+ if (dlen > OFP_ERRDATA_MAX)
+ dlen = OFP_ERRDATA_MAX;
+ if (ibuf_add(obuf, ibuf_seek(ibuf, 0, dlen), dlen) == -1)
+ return (-1);
+
+ header->oh_version = OFP_V_1_3;
+ header->oh_type = OFP_T_ERROR;
+ header->oh_length = htons(ibuf_length(obuf));
+ header->oh_xid = oh->oh_xid;
+ if (ofp13_validate(sc, &con->con_peer, &con->con_local, header,
+ obuf) == -1) {
+ ibuf_release(obuf);
+ return (-1);
+ }
+
+ rv = ofp_output(con, NULL, obuf);
+ ibuf_release(obuf);
+ return (rv);
+}
+
/*
* The valid commands for groups are:
* OFP_GROUPCMD_{ADD,MODIFY,DELETE}
@@ -2233,3 +2287,61 @@ oxm_ipv6exthdr(struct ibuf *ibuf, int hasmask, uint16_t exthdr, uint16_t mask)
}
return (0);
}
+
+int
+ofp_multipart_add(struct switch_connection *con, uint32_t xid, uint8_t type)
+{
+ struct multipart_message *mm;
+
+ /* A multipart reply have the same xid and type in all parts. */
+ SLIST_FOREACH(mm, &con->con_mmlist, mm_entry) {
+ if (mm->mm_xid != xid)
+ continue;
+ if (mm->mm_type != type)
+ return (-1);
+
+ return (0);
+ }
+
+ if ((mm = calloc(1, sizeof(*mm))) == NULL)
+ return (-1);
+
+ mm->mm_xid = xid;
+ mm->mm_type = type;
+ SLIST_INSERT_HEAD(&con->con_mmlist, mm, mm_entry);
+ return (0);
+}
+
+void
+ofp_multipart_del(struct switch_connection *con, uint32_t xid)
+{
+ struct multipart_message *mm;
+
+ SLIST_FOREACH(mm, &con->con_mmlist, mm_entry)
+ if (mm->mm_xid == xid)
+ break;
+
+ if (mm == NULL)
+ return;
+
+ ofp_multipart_free(con, mm);
+}
+
+void
+ofp_multipart_free(struct switch_connection *con,
+ struct multipart_message *mm)
+{
+ SLIST_REMOVE(&con->con_mmlist, mm, multipart_message, mm_entry);
+ free(mm);
+}
+
+void
+ofp_multipart_clear(struct switch_connection *con)
+{
+ struct multipart_message *mm;
+
+ while (!SLIST_EMPTY(&con->con_mmlist)) {
+ mm = SLIST_FIRST(&con->con_mmlist);
+ ofp_multipart_free(con, mm);
+ }
+}
diff --git a/usr.sbin/switchd/ofrelay.c b/usr.sbin/switchd/ofrelay.c
index eacf701792b..381b3c648aa 100644
--- a/usr.sbin/switchd/ofrelay.c
+++ b/usr.sbin/switchd/ofrelay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofrelay.c,v 1.4 2016/10/05 15:28:15 reyk Exp $ */
+/* $OpenBSD: ofrelay.c,v 1.5 2016/10/07 08:31:08 rzalamena Exp $ */
/*
* Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org>
@@ -99,6 +99,7 @@ ofrelay_close(struct switch_connection *con)
TAILQ_REMOVE(&sc->sc_conns, con, con_entry);
ofrelay_sessions--;
+ ofp_multipart_clear(con);
switch_remove(con->con_sc, con->con_switch);
msgbuf_clear(&con->con_wbuf);
ibuf_release(con->con_ibuf);
@@ -477,6 +478,7 @@ ofrelay_attach(struct switch_server *srv, int s, struct sockaddr *sa)
con->con_id = ++ofrelay_conid;
con->con_instance = ps->ps_instance + 1;
con->con_srv = srv;
+ SLIST_INIT(&con->con_mmlist);
memcpy(&con->con_peer, sa, sa->sa_len);
con->con_port = htons(socket_getport(&con->con_peer));
diff --git a/usr.sbin/switchd/switchd.h b/usr.sbin/switchd/switchd.h
index 591c35398cb..aedbfb6abeb 100644
--- a/usr.sbin/switchd/switchd.h
+++ b/usr.sbin/switchd/switchd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: switchd.h,v 1.13 2016/09/30 12:48:27 reyk Exp $ */
+/* $OpenBSD: switchd.h,v 1.14 2016/10/07 08:31:08 rzalamena Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -67,6 +67,15 @@ struct switch_control {
};
RB_HEAD(switch_head, switch_control);
+struct multipart_message {
+ SLIST_ENTRY(multipart_message)
+ mm_entry;
+
+ uint32_t mm_xid;
+ uint8_t mm_type;
+};
+SLIST_HEAD(multipart_list, multipart_message);
+
struct switch_connection {
unsigned int con_id;
unsigned int con_instance;
@@ -88,6 +97,8 @@ struct switch_connection {
struct switchd *con_sc;
struct switch_server *con_srv;
+ struct multipart_list con_mmlist;
+
TAILQ_ENTRY(switch_connection)
con_entry;
};
@@ -219,6 +230,13 @@ int ofp_validate_header(struct switchd *,
struct ofp_header *, uint8_t);
int ofp_input(struct switch_connection *, struct ibuf *);
+int ofp_multipart_add(struct switch_connection *, uint32_t,
+ uint8_t);
+void ofp_multipart_del(struct switch_connection *, uint32_t);
+void ofp_multipart_free(struct switch_connection *,
+ struct multipart_message *);
+void ofp_multipart_clear(struct switch_connection *);
+
/* ofp10.c */
int ofp10_hello(struct switchd *, struct switch_connection *,
struct ofp_header *, struct ibuf *);