summaryrefslogtreecommitdiff
path: root/usr.sbin/switchd
diff options
context:
space:
mode:
authorRafael Zalamena <rzalamena@cvs.openbsd.org>2016-11-17 09:42:12 +0000
committerRafael Zalamena <rzalamena@cvs.openbsd.org>2016-11-17 09:42:12 +0000
commit6f09aefc3da8aaa3de36589d4e9beae41b901cad (patch)
treeed71b11550659b6da282095ab30fa65f55e93445 /usr.sbin/switchd
parentbcb3d1a1d33aba1147ad94a8419ef430870dc55b (diff)
Added the missing code to build flow-mod messages and to install
table-miss by default for switch(4). ok reyk@
Diffstat (limited to 'usr.sbin/switchd')
-rw-r--r--usr.sbin/switchd/ofp13.c97
-rw-r--r--usr.sbin/switchd/ofp_common.c21
-rw-r--r--usr.sbin/switchd/switchd.h8
3 files changed, 123 insertions, 3 deletions
diff --git a/usr.sbin/switchd/ofp13.c b/usr.sbin/switchd/ofp13.c
index 07dc6034893..a39bcff23e4 100644
--- a/usr.sbin/switchd/ofp13.c
+++ b/usr.sbin/switchd/ofp13.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofp13.c,v 1.25 2016/11/07 13:27:11 rzalamena Exp $ */
+/* $OpenBSD: ofp13.c,v 1.26 2016/11/17 09:42:11 rzalamena Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -104,6 +104,8 @@ int ofp13_setconfig_validate(struct switchd *,
struct ofp_header *, struct ibuf *);
int ofp13_setconfig(struct switchd *, struct switch_connection *,
uint16_t, uint16_t);
+int ofp13_tablemiss_sendctrl(struct switchd *, struct switch_connection *,
+ uint8_t);
struct ofp_callback ofp13_callbacks[] = {
{ OFP_T_HELLO, ofp13_hello, NULL },
@@ -641,6 +643,9 @@ ofp13_features_reply(struct switchd *sc, struct switch_connection *con,
ofp13_setconfig(sc, con, OFP_CONFIG_FRAG_NORMAL,
OFP_CONTROLLER_MAXLEN_NO_BUFFER);
+ /* Use table '0' for switch(4) and '100' for HP 3800. */
+ ofp13_tablemiss_sendctrl(sc, con, 0);
+
return (0);
}
@@ -1863,3 +1868,93 @@ ofp13_featuresrequest(struct switchd *sc, struct switch_connection *con)
ibuf_free(ibuf);
return (rv);
}
+
+/*
+ * Flow modification message.
+ *
+ * After the flow-mod header we have N OXM filters to match packets, when
+ * you finish adding them you must update match header:
+ * fm_match.om_length = sizeof(fm_match) + OXM length.
+ *
+ * Then you must add flow instructions and update the OFP header length:
+ * fm_oh.oh_length =
+ * sizeof(*fm) + (fm_match.om_len - sizeof(fm_match)) + instructionslen.
+ * or
+ * fm_oh.oh_length = ibuf_length(ibuf).
+ *
+ * Note on match payload:
+ * After adding all matches and before starting to insert instructions you
+ * must add the mandatory padding to fm_match. You can calculate the padding
+ * size with this formula:
+ * padsize = OFP_ALIGN(fm_match.om_length) - fm_match.om_length;
+ *
+ * Note on Table-miss:
+ * To make a table miss you need to set priority 0 and don't add any
+ * matches, just instructions.
+ */
+struct ofp_flow_mod *
+ofp13_flowmod(struct switch_connection *con, struct ibuf *ibuf,
+ uint8_t cmd, uint8_t table, uint16_t idleto, uint16_t hardto,
+ uint16_t prio)
+{
+ struct ofp_flow_mod *fm;
+
+ if ((fm = ibuf_advance(ibuf, sizeof(*fm))) == NULL)
+ return (NULL);
+
+ fm->fm_oh.oh_version = OFP_V_1_3;
+ fm->fm_oh.oh_type = OFP_T_FLOW_MOD;
+ fm->fm_oh.oh_length = htons(sizeof(*fm));
+ fm->fm_oh.oh_xid = htonl(con->con_xidnxt++);
+ fm->fm_match.om_type = htons(OFP_MATCH_OXM);
+ fm->fm_match.om_length = htons(sizeof(fm->fm_match));
+ return (fm);
+}
+
+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;
+
+ if ((ibuf = ibuf_static()) == NULL)
+ return (-1);
+
+ fm = ofp13_flowmod(con, ibuf, OFP_FLOWCMD_ADD, table, 0, 0, 0);
+ if (fm == NULL)
+ goto done;
+
+ 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));
+
+ if (oi == NULL ||
+ action_output(ibuf, OFP_PORT_CONTROLLER,
+ OFP_CONTROLLER_MAXLEN_MAX) == -1)
+ goto done;
+ iend = ibuf->wpos;
+
+ /* Set header sizes. */
+ oi->i_len = htons(iend - istart);
+ fm->fm_oh.oh_length = htons(ibuf_length(ibuf));
+
+ if (ofp13_validate(sc, &con->con_local, &con->con_peer, &fm->fm_oh,
+ ibuf) != 0)
+ goto done;
+
+ rv = ofp_output(con, NULL, ibuf);
+
+ done:
+ ibuf_release(ibuf);
+ return (rv);
+}
diff --git a/usr.sbin/switchd/ofp_common.c b/usr.sbin/switchd/ofp_common.c
index d3f882442ef..09047dd34b9 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.3 2016/11/11 22:07:40 reyk Exp $ */
+/* $OpenBSD: ofp_common.c,v 1.4 2016/11/17 09:42:11 rzalamena Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -881,6 +881,25 @@ oxm_ipv6exthdr(struct ibuf *ibuf, int hasmask, uint16_t exthdr, uint16_t mask)
return (0);
}
+/*
+ * Appends a new instruction with hlen size.
+ *
+ * Remember to set the instruction length (i->i_len) if it has more data,
+ * like ofp_instruction_actions, ofp_instruction_goto_table etc...
+ */
+struct ofp_instruction *
+ofp_instruction(struct ibuf *ibuf, uint16_t type, uint16_t hlen)
+{
+ struct ofp_instruction *oi;
+
+ if ((oi = ibuf_advance(ibuf, hlen)) == NULL)
+ return (NULL);
+
+ oi->i_type = htons(type);
+ oi->i_len = htons(hlen);
+ return (oi);
+}
+
int
ofp_multipart_add(struct switch_connection *con, uint32_t xid, uint8_t type)
{
diff --git a/usr.sbin/switchd/switchd.h b/usr.sbin/switchd/switchd.h
index f1b34246f24..1665e509c0d 100644
--- a/usr.sbin/switchd/switchd.h
+++ b/usr.sbin/switchd/switchd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: switchd.h,v 1.20 2016/11/15 09:05:14 reyk Exp $ */
+/* $OpenBSD: switchd.h,v 1.21 2016/11/17 09:42:11 rzalamena Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -251,6 +251,9 @@ int ofp13_table_features(struct switchd *,
struct switch_connection *, uint8_t);
int ofp13_featuresrequest(struct switchd *,
struct switch_connection *);
+struct ofp_flow_mod *
+ ofp13_flowmod(struct switch_connection *, struct ibuf *,
+ uint8_t, uint8_t, uint16_t, uint16_t, uint16_t);
/* ofp_common.c */
int ofp_validate_header(struct switchd *,
@@ -308,6 +311,9 @@ int oxm_mplstc(struct ibuf *, uint8_t);
int oxm_mplsbos(struct ibuf *, uint8_t);
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);
+
/* ofcconn.c */
void ofcconn(struct privsep *, struct privsep_proc *);