summaryrefslogtreecommitdiff
path: root/usr.sbin/switchd
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2016-11-17 12:40:57 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2016-11-17 12:40:57 +0000
commitd6a5d814dc7c368cdb5a8397237c4de9e5738eb1 (patch)
treee46654fe94a2261773b8102a5cf4177eb8508c66 /usr.sbin/switchd
parentc22f834714b28fdff9f1725641d1018a72b0cfb0 (diff)
Add an abstraction layer / API to create flows including all matches
and instructions. This makes it easier to integrate flow features in switchd and switchctl later. Written and committed during a long flight. OK rzalamena@
Diffstat (limited to 'usr.sbin/switchd')
-rw-r--r--usr.sbin/switchd/ofp13.c64
-rw-r--r--usr.sbin/switchd/ofp_common.c250
-rw-r--r--usr.sbin/switchd/switchd.h33
-rw-r--r--usr.sbin/switchd/types.h13
4 files changed, 321 insertions, 39 deletions
diff --git a/usr.sbin/switchd/ofp13.c b/usr.sbin/switchd/ofp13.c
index 3ff41540791..fcf508a7de2 100644
--- a/usr.sbin/switchd/ofp13.c
+++ b/usr.sbin/switchd/ofp13.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofp13.c,v 1.27 2016/11/17 10:15:05 reyk Exp $ */
+/* $OpenBSD: ofp13.c,v 1.28 2016/11/17 12:40:56 reyk Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -1924,47 +1924,41 @@ int
ofp13_tablemiss_sendctrl(struct switchd *sc, struct switch_connection *con,
uint8_t table)
{
- struct ofp_flow_mod *fm;
- struct ofp_instruction *oi;
- struct ibuf *ibuf;
- size_t istart, iend;
- int padding;
- int rv = -1;
+ struct oflowmod_ctx ctx;
+ struct ibuf *ibuf;
+ int ret;
- if ((ibuf = ibuf_static()) == NULL)
- return (-1);
+ if ((ibuf = oflowmod_open(&ctx, con, NULL, OFP_V_1_3)) == NULL)
+ goto err;
- fm = ofp13_flowmod(con, ibuf, OFP_FLOWCMD_ADD, table, 0, 0, 0);
- if (fm == NULL)
- goto done;
+ if (oflowmod_iopen(&ctx) == -1)
+ goto err;
- padding = OFP_ALIGN(sizeof(fm->fm_match)) - sizeof(fm->fm_match);
- if (padding && ibuf_advance(ibuf, padding) == NULL)
- goto done;
-
- istart = ibuf->wpos;
- oi = (struct ofp_instruction *)ofp_instruction(ibuf,
- OFP_INSTRUCTION_T_APPLY_ACTIONS,
- sizeof(struct ofp_instruction_actions));
+ /* Update header */
+ ctx.ctx_fm->fm_table_id = table;
- if (oi == NULL ||
- action_output(ibuf, OFP_PORT_CONTROLLER,
+ if (oflowmod_instruction(&ctx,
+ OFP_INSTRUCTION_T_APPLY_ACTIONS) == -1)
+ goto err;
+ if (action_output(ibuf, OFP_PORT_CONTROLLER,
OFP_CONTROLLER_MAXLEN_MAX) == -1)
- goto done;
- iend = ibuf->wpos;
+ goto err;
- /* Set header sizes. */
- oi->i_len = htons(iend - istart);
- fm->fm_oh.oh_length = htons(ibuf_length(ibuf));
+ if (oflowmod_iclose(&ctx) == -1)
+ goto err;
+ if (oflowmod_close(&ctx) == -1)
+ goto err;
- if (ofp13_validate(sc, &con->con_local, &con->con_peer, &fm->fm_oh,
- ibuf) != 0)
- goto done;
+ if (ofp13_validate(sc, &con->con_local, &con->con_peer,
+ &ctx.ctx_fm->fm_oh, ibuf) != 0)
+ goto err;
- rv = ofp_output(con, NULL, ibuf);
-
- done:
+ ret = ofp_output(con, NULL, ibuf);
ibuf_release(ibuf);
- return (rv);
-}
+ return (ret);
+
+ err:
+ (void)oflowmod_err(&ctx, __func__, __LINE__);
+ return (-1);
+}
diff --git a/usr.sbin/switchd/ofp_common.c b/usr.sbin/switchd/ofp_common.c
index a2aa8446224..765ca9d31bf 100644
--- a/usr.sbin/switchd/ofp_common.c
+++ b/usr.sbin/switchd/ofp_common.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofp_common.c,v 1.5 2016/11/17 10:05:44 reyk Exp $ */
+/* $OpenBSD: ofp_common.c,v 1.6 2016/11/17 12:40:56 reyk Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -974,3 +974,251 @@ ofp_multipart_clear(struct switch_connection *con)
ofp_multipart_free(con, mm);
}
}
+
+int
+oflowmod_state(struct oflowmod_ctx *ctx, unsigned int old, unsigned int new)
+{
+ if (ctx->ctx_state != old)
+ return (-1);
+ ctx->ctx_state = new;
+ return (0);
+}
+
+int
+oflowmod_err(struct oflowmod_ctx *ctx, const char *func, int line)
+{
+ log_debug("%s: function %s line %d state %d",
+ __func__, func, line, ctx->ctx_state);
+
+ if (ctx->ctx_state >= OFMCTX_ERR)
+ return (-1);
+ if (ctx->ctx_flags & OFMCTX_IBUF)
+ ibuf_release(ctx->ctx_ibuf);
+ ctx->ctx_state = OFMCTX_ERR;
+ return (-1);
+}
+
+struct ibuf *
+oflowmod_open(struct oflowmod_ctx *ctx, struct switch_connection *con,
+ struct ibuf *ibuf, uint8_t version)
+{
+ struct ofp_flow_mod *fm;
+ struct switch_connection conb;
+
+ switch (version) {
+ case OFP_V_0:
+ case OFP_V_1_3:
+ version = OFP_V_1_3;
+ break;
+ default:
+ log_warnx("%s: unsupported version 0x%02x", __func__, version);
+ return (NULL);
+ }
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ if (oflowmod_state(ctx, OFMCTX_INIT, OFMCTX_OPEN) == -1)
+ goto err;
+
+ if (ibuf == NULL) {
+ ctx->ctx_flags |= OFMCTX_IBUF;
+ if ((ibuf = ibuf_static()) == NULL)
+ goto err;
+ }
+
+ ctx->ctx_ibuf = ibuf;
+ ctx->ctx_start = ibuf->wpos;
+
+ /*
+ * The connection is not strictly required and might not be
+ * available in other places; just default to an xid 0.
+ */
+ if (con == NULL) {
+ con = &conb;
+ memset(con, 0, sizeof(*con));
+ }
+
+ /* uses defaults, can be changed by accessing fm later */
+ if ((fm = ofp13_flowmod(con, ibuf,
+ OFP_FLOWCMD_ADD, 0, 0, 0, 0)) == NULL)
+ goto err;
+
+ ctx->ctx_fm = fm;
+
+ return (ctx->ctx_ibuf);
+
+ err:
+ (void)oflowmod_err(ctx, __func__, __LINE__);
+ return (NULL);
+}
+
+int
+oflowmod_mopen(struct oflowmod_ctx *ctx)
+{
+ if (oflowmod_state(ctx, OFMCTX_OPEN, OFMCTX_MOPEN) == -1)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ ctx->ctx_ostart = ctx->ctx_start +
+ offsetof(struct ofp_flow_mod, fm_match);
+
+ return (0);
+}
+
+int
+oflowmod_mclose(struct oflowmod_ctx *ctx)
+{
+ struct ibuf *ibuf = ctx->ctx_ibuf;
+ struct ofp_flow_mod *fm = ctx->ctx_fm;
+ size_t omlen, padding;
+
+ if (oflowmod_state(ctx, OFMCTX_MOPEN, OFMCTX_MCLOSE) == -1)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ ctx->ctx_oend = ibuf->wpos;
+ omlen = ctx->ctx_oend - ctx->ctx_ostart;
+
+ /* Update match length */
+ fm->fm_match.om_length = htons(omlen);
+
+ padding = OFP_ALIGN(omlen) - omlen;
+ if (padding) {
+ ctx->ctx_oend += padding;
+ if (ibuf_advance(ibuf, padding) == NULL)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+ }
+
+ return (0);
+}
+
+int
+oflowmod_iopen(struct oflowmod_ctx *ctx)
+{
+ struct ibuf *ibuf = ctx->ctx_ibuf;
+
+ if (ctx->ctx_state < OFMCTX_MOPEN &&
+ (oflowmod_mopen(ctx) == -1 ||
+ oflowmod_mclose(ctx) == -1))
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ if (oflowmod_state(ctx, OFMCTX_MCLOSE, OFMCTX_IOPEN) == -1)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ ctx->ctx_istart = ibuf->wpos;
+
+ return (0);
+}
+
+int
+oflowmod_instruction(struct oflowmod_ctx *ctx, unsigned int type)
+{
+ struct ibuf *ibuf = ctx->ctx_ibuf;
+ struct ofp_instruction *oi;
+ size_t len;
+
+ if (oflowmod_state(ctx, OFMCTX_IOPEN, OFMCTX_IOPEN) == -1)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ if (ctx->ctx_oi != NULL && oflowmod_instructionclose(ctx) == -1)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ ctx->ctx_oioff = ibuf->wpos;
+
+ switch (type) {
+ case OFP_INSTRUCTION_T_GOTO_TABLE:
+ len = sizeof(struct ofp_instruction_goto_table);
+ break;
+ case OFP_INSTRUCTION_T_WRITE_META:
+ len = sizeof(struct ofp_instruction_write_metadata);
+ break;
+ case OFP_INSTRUCTION_T_WRITE_ACTIONS:
+ case OFP_INSTRUCTION_T_APPLY_ACTIONS:
+ case OFP_INSTRUCTION_T_CLEAR_ACTIONS:
+ len = sizeof(struct ofp_instruction_actions);
+ break;
+ case OFP_INSTRUCTION_T_METER:
+ len = sizeof(struct ofp_instruction_meter);
+ break;
+ case OFP_INSTRUCTION_T_EXPERIMENTER:
+ len = sizeof(struct ofp_instruction_experimenter);
+ break;
+ default:
+ return (oflowmod_err(ctx, __func__, __LINE__));
+ }
+
+ if ((oi = ofp_instruction(ibuf, type, len)) == NULL)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ ctx->ctx_oi = oi;
+
+ return (0);
+}
+
+int
+oflowmod_instructionclose(struct oflowmod_ctx *ctx)
+{
+ struct ibuf *ibuf = ctx->ctx_ibuf;
+ struct ofp_instruction *oi = ctx->ctx_oi;
+ size_t oilen;
+
+ if (ctx->ctx_state < OFMCTX_IOPEN || oi == NULL)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ oilen = ibuf->wpos - ctx->ctx_oioff;
+
+ if (oilen > UINT16_MAX)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ oi->i_len = htons(oilen);
+ ctx->ctx_oi = NULL;
+
+ return (0);
+}
+
+int
+oflowmod_iclose(struct oflowmod_ctx *ctx)
+{
+ struct ibuf *ibuf = ctx->ctx_ibuf;
+
+ if (oflowmod_state(ctx, OFMCTX_IOPEN, OFMCTX_ICLOSE) == -1)
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+ if (ctx->ctx_oi != NULL && oflowmod_instructionclose(ctx) == -1)
+ return (-1);
+
+ ctx->ctx_iend = ibuf->wpos;
+
+ return (0);
+}
+
+int
+oflowmod_close(struct oflowmod_ctx *ctx)
+{
+ struct ofp_flow_mod *fm = ctx->ctx_fm;
+ struct ibuf *ibuf = ctx->ctx_ibuf;
+ size_t len;
+
+ /* No matches, calculate default */
+ if (ctx->ctx_state < OFMCTX_MOPEN &&
+ (oflowmod_mopen(ctx) == -1 ||
+ oflowmod_mclose(ctx) == -1))
+ goto err;
+
+ /* No instructions, calculate default */
+ if (ctx->ctx_state < OFMCTX_IOPEN &&
+ (oflowmod_iopen(ctx) == -1 ||
+ oflowmod_iclose(ctx) == -1))
+ goto err;
+
+ if (oflowmod_state(ctx, OFMCTX_ICLOSE, OFMCTX_CLOSE) == -1)
+ goto err;
+
+ /* Update length */
+ len = ibuf->wpos - ctx->ctx_start;
+ fm->fm_oh.oh_length = htons(len);
+
+ return (0);
+
+ err:
+ return (oflowmod_err(ctx, __func__, __LINE__));
+
+}
diff --git a/usr.sbin/switchd/switchd.h b/usr.sbin/switchd/switchd.h
index dfdc01c5d45..bb7ec2d25ae 100644
--- a/usr.sbin/switchd/switchd.h
+++ b/usr.sbin/switchd/switchd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: switchd.h,v 1.22 2016/11/17 10:05:44 reyk Exp $ */
+/* $OpenBSD: switchd.h,v 1.23 2016/11/17 12:40:56 reyk Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -154,6 +154,22 @@ struct ofp_callback {
#define SWITCHD_OPT_VERBOSE 0x01
#define SWITCHD_OPT_NOACTION 0x04
+struct oflowmod_ctx {
+ uint8_t ctx_flags;
+#define OFMCTX_IBUF 0x01
+ enum oflowmod_state ctx_state;
+
+ struct ibuf *ctx_ibuf;
+ struct ofp_flow_mod *ctx_fm;
+ size_t ctx_start;
+ size_t ctx_ostart;
+ size_t ctx_oend;
+ size_t ctx_istart;
+ size_t ctx_iend;
+ size_t ctx_oioff;
+ struct ofp_instruction *ctx_oi;
+};
+
/* switchd.c */
int switchd_socket(struct sockaddr *, int);
int switchd_listen(struct sockaddr *);
@@ -316,7 +332,20 @@ int oxm_tunnelid(struct ibuf *, int, uint64_t, uint64_t);
int oxm_ipv6exthdr(struct ibuf *, int, uint16_t, uint16_t);
struct ofp_instruction *
ofp_instruction(struct ibuf *, uint16_t, uint16_t);
-
+struct ibuf *
+ oflowmod_open(struct oflowmod_ctx *,
+ struct switch_connection *, struct ibuf *, uint8_t);
+int oflowmod_close(struct oflowmod_ctx *);
+int oflowmod_mopen(struct oflowmod_ctx *);
+int oflowmod_mclose(struct oflowmod_ctx *);
+int oflowmod_iopen(struct oflowmod_ctx *);
+int oflowmod_iclose(struct oflowmod_ctx *);
+int oflowmod_instruction(struct oflowmod_ctx *, unsigned int);
+
+int oflowmod_instructionclose(struct oflowmod_ctx *);
+int oflowmod_state(struct oflowmod_ctx *,
+ unsigned int, unsigned int);
+int oflowmod_err(struct oflowmod_ctx *, const char *, int);
/* ofcconn.c */
void ofcconn(struct privsep *, struct privsep_proc *);
diff --git a/usr.sbin/switchd/types.h b/usr.sbin/switchd/types.h
index b9d8b81c95b..0ebf1e708e5 100644
--- a/usr.sbin/switchd/types.h
+++ b/usr.sbin/switchd/types.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: types.h,v 1.7 2016/10/12 19:07:42 reyk Exp $ */
+/* $OpenBSD: types.h,v 1.8 2016/11/17 12:40:56 reyk Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -97,6 +97,17 @@ enum switch_conn_type {
SWITCH_CONN_TLS
};
+enum oflowmod_state {
+ OFMCTX_INIT,
+ OFMCTX_OPEN,
+ OFMCTX_MOPEN,
+ OFMCTX_MCLOSE,
+ OFMCTX_IOPEN,
+ OFMCTX_ICLOSE,
+ OFMCTX_CLOSE,
+ OFMCTX_ERR
+};
+
#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif