diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2016-11-17 12:40:57 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2016-11-17 12:40:57 +0000 |
commit | d6a5d814dc7c368cdb5a8397237c4de9e5738eb1 (patch) | |
tree | e46654fe94a2261773b8102a5cf4177eb8508c66 /usr.sbin/switchd | |
parent | c22f834714b28fdff9f1725641d1018a72b0cfb0 (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.c | 64 | ||||
-rw-r--r-- | usr.sbin/switchd/ofp_common.c | 250 | ||||
-rw-r--r-- | usr.sbin/switchd/switchd.h | 33 | ||||
-rw-r--r-- | usr.sbin/switchd/types.h | 13 |
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 |