From: reyk Date: Wed, 20 Jul 2016 14:15:08 +0000 (+0000) Subject: Update OpenFlow 1.3 stub based on the 1.0 code. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ed40986634627749ff285f6c6d7eef8ce39673eb;p=openbsd Update OpenFlow 1.3 stub based on the 1.0 code. --- diff --git a/usr.sbin/switchd/ofp.c b/usr.sbin/switchd/ofp.c index eeb72357839..8b8778fc20b 100644 --- a/usr.sbin/switchd/ofp.c +++ b/usr.sbin/switchd/ofp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofp.c,v 1.2 2016/07/19 18:11:08 reyk Exp $ */ +/* $OpenBSD: ofp.c,v 1.3 2016/07/20 14:15:08 reyk Exp $ */ /* * Copyright (c) 2013-2016 Reyk Floeter @@ -71,6 +71,7 @@ ofp(struct privsep *ps, struct privsep_proc *p) pid = proc_run(ps, p, procs, nitems(procs), ofp_init, NULL); close(srv->srv_fd); + close(sc->sc_tap); return (pid); } diff --git a/usr.sbin/switchd/ofp10.c b/usr.sbin/switchd/ofp10.c index bd89686b2df..d76249ca59c 100644 --- a/usr.sbin/switchd/ofp10.c +++ b/usr.sbin/switchd/ofp10.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofp10.c,v 1.2 2016/07/19 18:11:08 reyk Exp $ */ +/* $OpenBSD: ofp10.c,v 1.3 2016/07/20 14:15:08 reyk Exp $ */ /* * Copyright (c) 2013-2016 Reyk Floeter @@ -48,6 +48,9 @@ int ofp10_error(struct switchd *, struct switch_connection *, int ofp10_packet_match(struct packet *, struct ofp10_match *, unsigned int); +void ofp10_debug_header(struct switchd *, + struct sockaddr_storage *, struct sockaddr_storage *, + struct ofp_header *); int ofp10_debug_packet_in(struct switchd *, struct sockaddr_storage *, struct sockaddr_storage *, struct ofp_header *, struct ibuf *); diff --git a/usr.sbin/switchd/ofp13.c b/usr.sbin/switchd/ofp13.c index 0747d92f15b..8c850a52e67 100644 --- a/usr.sbin/switchd/ofp13.c +++ b/usr.sbin/switchd/ofp13.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofp13.c,v 1.1 2016/07/19 16:54:26 reyk Exp $ */ +/* $OpenBSD: ofp13.c,v 1.2 2016/07/20 14:15:08 reyk Exp $ */ /* * Copyright (c) 2013-2016 Reyk Floeter @@ -16,13 +16,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* XXX not implemented, this is just a stub */ - #include #include #include +#include +#include #include +#include #include #include @@ -34,86 +35,401 @@ #include #include "ofp.h" -#include "ofp10.h" #include "switchd.h" +#include "ofp_map.h" + +int ofp13_hello(struct switchd *, struct switch_connection *, + struct ofp_header *, struct ibuf *); +int ofp13_echo_request(struct switchd *, struct switch_connection *, + struct ofp_header *, struct ibuf *); +int ofp13_packet_in(struct switchd *, struct switch_connection *, + struct ofp_header *, struct ibuf *); +int ofp13_error(struct switchd *, struct switch_connection *, + struct ofp_header *, struct ibuf *); + +int ofp13_packet_match(struct packet *, struct ofp_match *, unsigned int); + +void ofp13_debug(struct switchd *, + struct sockaddr_storage *, struct sockaddr_storage *, + struct ofp_header *, struct ibuf *); +void ofp13_debug_header(struct switchd *, + struct sockaddr_storage *, struct sockaddr_storage *, + struct ofp_header *); +int ofp13_debug_packet_in(struct switchd *, + struct sockaddr_storage *, struct sockaddr_storage *, + struct ofp_header *, struct ibuf *); +int ofp13_debug_packet_out(struct switchd *, + struct sockaddr_storage *, struct sockaddr_storage *, + struct ofp_header *, struct ibuf *); +int ofp13_debug_error(struct switchd *, + struct sockaddr_storage *, struct sockaddr_storage *, + struct ofp_header *, struct ibuf *); + +struct ofp_callback ofp13_callbacks[] = { + { OFP_T_HELLO, ofp13_hello, NULL }, + { OFP_T_ERROR, NULL, ofp13_debug_error }, + { OFP_T_ECHO_REQUEST, ofp13_echo_request, NULL }, + { OFP_T_ECHO_REPLY, NULL, NULL }, + { OFP_T_EXPERIMENTER, NULL, NULL }, + { OFP_T_FEATURES_REQUEST, NULL, NULL }, + { OFP_T_FEATURES_REPLY, NULL, NULL }, + { OFP_T_GET_CONFIG_REQUEST, NULL, NULL }, + { OFP_T_GET_CONFIG_REPLY, NULL, NULL }, + { OFP_T_SET_CONFIG, NULL, NULL }, + { OFP_T_PACKET_IN, ofp13_packet_in, ofp13_debug_packet_in }, + { OFP_T_FLOW_REMOVED, NULL, NULL }, + { OFP_T_PORT_STATUS, NULL, NULL }, + { OFP_T_PACKET_OUT, NULL, ofp13_debug_packet_out }, + { OFP_T_FLOW_MOD, NULL, NULL }, + { OFP_T_GROUP_MOD, NULL, NULL }, + { OFP_T_PORT_MOD, NULL, NULL }, + { OFP_T_TABLE_MOD, NULL, NULL }, + { OFP_T_MULTIPART_REQUEST, NULL, NULL }, + { OFP_T_MULTIPART_REPLY, NULL, NULL }, + { OFP_T_BARRIER_REQUEST, NULL, NULL }, + { OFP_T_BARRIER_REPLY, NULL, NULL }, + { OFP_T_QUEUE_GET_CONFIG_REQUEST, NULL, NULL }, + { OFP_T_QUEUE_GET_CONFIG_REPLY, NULL, NULL }, + { OFP_T_ROLE_REQUEST, NULL, NULL }, + { OFP_T_ROLE_REPLY, NULL, NULL }, + { OFP_T_GET_ASYNC_REQUEST, NULL, NULL }, + { OFP_T_GET_ASYNC_REPLY, NULL, NULL }, + { OFP_T_SET_ASYNC, NULL, NULL }, + { OFP_T_METER_MOD, NULL, NULL }, +}; + +void +ofp13_debug_header(struct switchd *sc, + struct sockaddr_storage *src, struct sockaddr_storage *dst, + struct ofp_header *oh) +{ + log_debug("%s > %s: version %s type %s length %u xid %u", + print_host(src, NULL, 0), + print_host(dst, NULL, 0), + print_map(oh->oh_version, ofp_v_map), + print_map(oh->oh_type, ofp_t_map), + ntohs(oh->oh_length), ntohl(oh->oh_xid)); +} void ofp13_debug(struct switchd *sc, struct sockaddr_storage *src, struct sockaddr_storage *dst, struct ofp_header *oh, struct ibuf *ibuf) { - struct ofp_packet_in pin; -#if 0 + ofp13_debug_header(sc, src, dst, oh); + + if (ibuf == NULL || + oh->oh_version != OFP_V_1_3 || + oh->oh_type >= OFP_T_TYPE_MAX || + ofp13_callbacks[oh->oh_type].debug == NULL) + return; + if (ofp13_callbacks[oh->oh_type].debug(sc, src, dst, oh, ibuf) != 0) + goto fail; + + return; + fail: + log_debug("\tinvalid packet"); +} + +int +ofp13_debug_packet_in(struct switchd *sc, + struct sockaddr_storage *src, struct sockaddr_storage *dst, + struct ofp_header *oh, struct ibuf *ibuf) +{ + struct ofp_packet_in *pin; uint8_t *p; -#endif - uint8_t *buf; size_t len; + off_t off; - len = ibuf_length(ibuf); - buf = ibuf_data(ibuf); + off = 0; + if ((pin = ibuf_seek(ibuf, off, sizeof(*pin))) == NULL) + return (-1); + log_debug("\tbuffer %d length %u reason %s table %u cookie 0x%016llx", + ntohl(pin->pin_buffer_id), + ntohs(pin->pin_total_len), + print_map(ntohs(pin->pin_reason), ofp_pktin_map), + pin->pin_table_id, + be64toh(pin->pin_cookie)); + len = ntohs(pin->pin_total_len); + off += sizeof(*pin); + if ((p = ibuf_seek(ibuf, off, len)) == NULL) + return (-1); + if (sc->sc_tap != -1) + (void)write(sc->sc_tap, p, len); + return (0); +} + +int +ofp13_debug_packet_out(struct switchd *sc, + struct sockaddr_storage *src, struct sockaddr_storage *dst, + struct ofp_header *oh, struct ibuf *ibuf) +{ + struct ofp_packet_out *pout; + size_t len; + off_t off; + struct ofp_action_header *ah; + struct ofp_action_output *ao; - ofp10_debug_header(sc, src, dst, oh); + off = 0; + if ((pout = ibuf_seek(ibuf, off, sizeof(*pout))) == NULL) { + log_debug("%s: seek failed: length %zd", + __func__, ibuf_length(ibuf)); + return (-1); + } - if (oh->oh_version != OFP_V_1_3) - return; + log_debug("\tbuffer %d port %s " + "actions length %u", + ntohl(pout->pout_buffer_id), + print_map(ntohl(pout->pout_in_port), ofp_port_map), + ntohl(pout->pout_actions_len)); + len = ntohl(pout->pout_actions_len); - switch (oh->oh_type) { - case OFP_T_PACKET_IN: - if (len < sizeof(pin)) - goto fail; - memcpy(&pin, buf, sizeof(pin)); -#if 0 - log_debug("\tbuffer %d port 0x%08x " - "phy port 0x%08x length %u " - "reason %u table id %u", - ntohl(pin13.pin_buffer_id), - ntohl(pin13.pin_port), - ntohl(pin13.pin_phy_port), - ntohs(pin13.pin_total_len), - pin13.pin_reason, - pin13.pin_table_id); - if ((len - sizeof(pin)) < ntohs(pin.pin_total_len)) - goto fail; - if (sc->sc_tap != -1) { - p = (uint8_t *)&buf[sizeof(pin)]; - (void)write(sc->sc_tap, p, - ntohs(pin.pin_total_len)); + off += sizeof(*pout); + while ((ah = ibuf_seek(ibuf, off, len)) != NULL && + ntohs(ah->ah_len) >= (uint16_t)sizeof(*ah)) { + switch (ntohs(ah->ah_type)) { + case OFP_ACTION_OUTPUT: + ao = (struct ofp_action_output *)ah; + log_debug("\t\taction type %s length %d " + "port %s max length %d", + print_map(ntohs(ao->ao_type), ofp_action_map), + ntohs(ao->ao_len), + print_map(ntohs(ao->ao_port), ofp_port_map), + ntohs(ao->ao_max_len)); + break; + default: + log_debug("\t\taction type %s length %d", + print_map(ntohs(ah->ah_type), ofp_action_map), + ntohs(ah->ah_len)); + break; } -#endif - break; + if (pout->pout_buffer_id == (uint32_t)-1) + break; + off += ntohs(ah->ah_len); } - return; - fail: - log_debug("\tinvalid packet\n"); + return (0); } int -ofp13_input(struct switchd *sc, struct switch_connection *con, +ofp13_debug_error(struct switchd *sc, + struct sockaddr_storage *src, struct sockaddr_storage *dst, struct ofp_header *oh, struct ibuf *ibuf) { - uint8_t *buf; - ssize_t len; - - len = ibuf_length(ibuf); - buf = ibuf_data(ibuf); + struct ofp_error *err; + off_t off; + const char *code; - ofp13_debug(sc, &con->con_peer, &con->con_local, oh, ibuf); + off = 0; + if ((err = ibuf_seek(ibuf, off, sizeof(*err))) == NULL) { + log_debug("%s: seek failed: length %zd", + __func__, ibuf_length(ibuf)); + return (-1); + } - switch (oh->oh_type) { - case OFP_T_HELLO: - /* Echo back the received Hello packet */ - ofp_send(con, oh, NULL); - break; - case OFP_T_ECHO_REQUEST: - /* Echo reply */ - oh->oh_type = OFP_T_ECHO_REPLY; - ofp_send(con, oh, NULL); + switch (ntohs(err->err_type)) { + case OFP_ERRTYPE_FLOW_MOD_FAILED: + code = print_map(ntohs(err->err_code), ofp_errflowmod_map); break; default: - /* not implemented */ + code = NULL; break; } + log_debug("\terror type %s code %u%s%s", + print_map(ntohs(err->err_type), ofp_errtype_map), + ntohs(err->err_code), + code == NULL ? "" : ": ", + code == NULL ? "" : code); + return (0); } + +int +ofp13_input(struct switchd *sc, struct switch_connection *con, + struct ofp_header *oh, struct ibuf *ibuf) +{ + ofp13_debug(sc, &con->con_peer, &con->con_local, oh, ibuf); + + if (oh->oh_version != OFP_V_1_3 || + oh->oh_type >= OFP_T_TYPE_MAX) { + log_debug("unsupported packet"); + return (-1); + } + + if (ofp13_callbacks[oh->oh_type].cb == NULL) { + log_debug("message not supported: %s", + print_map(oh->oh_type, ofp_t_map)); + return (-1); + } + if (ofp13_callbacks[oh->oh_type].cb(sc, con, oh, ibuf) != 0) + return (-1); + + return (0); +} + +int +ofp13_hello(struct switchd *sc, struct switch_connection *con, + struct ofp_header *oh, struct ibuf *ibuf) +{ + if (oh->oh_version == OFP_V_1_3 && + switch_add(con) == NULL) { + log_debug("%s: failed to add switch", __func__); + ofp_close(con); + return (-1); + } + + /* Echo back the received Hello packet */ + oh->oh_version = OFP_V_1_3; + oh->oh_length = htons(sizeof(*oh)); + oh->oh_xid = htonl(con->con_xidnxt++); + ofp_send(con, oh, NULL); + ofp13_debug(sc, &con->con_local, &con->con_peer, oh, NULL); + + return (0); +} + +int +ofp13_echo_request(struct switchd *sc, struct switch_connection *con, + struct ofp_header *oh, struct ibuf *ibuf) +{ + /* Echo reply */ + oh->oh_type = OFP_T_ECHO_REPLY; + ofp13_debug(sc, &con->con_local, &con->con_peer, oh, NULL); + ofp_send(con, oh, NULL); + + return (0); +} + +int +ofp13_packet_match(struct packet *pkt, struct ofp_match *m, uint32_t flags) +{ +#if 0 + struct ether_header *eh = pkt->pkt_eh; + + bzero(m, sizeof(*m)); + m->m_wildcards = htonl(~flags); + + if ((flags & (OFP_WILDCARD_DL_SRC|OFP_WILDCARD_DL_DST)) && (eh == NULL)) + return (-1); + + if (flags & OFP_WILDCARD_DL_SRC) + memcpy(m->m_dl_src, eh->ether_shost, ETHER_ADDR_LEN); + if (flags & OFP_WILDCARD_DL_DST) + memcpy(m->m_dl_dst, eh->ether_dhost, ETHER_ADDR_LEN); +#endif + return (0); +} + +int +ofp13_packet_in(struct switchd *sc, struct switch_connection *con, + struct ofp_header *ih, struct ibuf *ibuf) +{ +#if 0 + struct ofp_packet_in *pin; + struct ofp_packet_out *pout; + struct ofp_action_output *ao; + struct ofp_flow_mod *fm; + struct ofp_header *oh; + struct packet pkt; + struct ibuf *obuf = NULL; + int ret = -1; + size_t len; + long srcport, dstport; + int addflow = 0; + int addpacket = 0; + + if ((pin = ibuf_getdata(ibuf, sizeof(*pin))) == NULL) + return (-1); + + bzero(&pkt, sizeof(pkt)); + len = ntohs(pin->pin_total_len); + srcport = ntohs(pin->pin_port); + + if ((dstport = packet_input(sc, con->con_switch, + srcport, ibuf, len, &pkt)) == -1 || + dstport > OFP_PORT_MAX) { + /* fallback to flooding */ + dstport = OFP_PORT_FLOOD; + } else if (srcport == dstport) { + /* + * silently drop looping packet + * (don't use OFP_PORT_INPUT here) + */ + dstport = OFP_PORT_ANY; + } + + if (dstport <= OFP_PORT_MAX) + addflow = 1; + + if ((obuf = ibuf_static()) == NULL) + goto done; + + again: + if (addflow) { + if ((fm = ibuf_advance(obuf, sizeof(*fm))) == NULL) + goto done; + + ofp13_packet_match(&pkt, &fm->fm_match, OFP_WILDCARD_DL_DST); + + oh = &fm->fm_oh; + fm->fm_cookie = 0; /* XXX should we set a cookie? */ + fm->fm_command = htons(OFP_FLOWCMD_ADD); + fm->fm_idle_timeout = htons(sc->sc_cache_timeout); + fm->fm_hard_timeout = 0; /* permanent */ + fm->fm_priority = 0; + fm->fm_buffer_id = pin->pin_buffer_id; + fm->fm_flags = htons(OFP_FLOWFLAG_SEND_FLOW_REMOVED); + if (pin->pin_buffer_id == (uint32_t)-1) + addpacket = 1; + } else { + if ((pout = ibuf_advance(obuf, sizeof(*pout))) == NULL) + goto done; + + oh = &pout->pout_oh; + pout->pout_buffer_id = pin->pin_buffer_id; + pout->pout_port = pin->pin_port; + pout->pout_actions_len = htons(sizeof(*ao)); + + if (pin->pin_buffer_id == (uint32_t)-1) + addpacket = 1; + } + + if ((ao = ibuf_advance(obuf, sizeof(*ao))) == NULL) + goto done; + ao->ao_type = htons(OFP_ACTION_OUTPUT); + ao->ao_len = htons(sizeof(*ao)); + ao->ao_port = htons((uint16_t)dstport); + ao->ao_max_len = 0; + + /* Add optional packet payload */ + if (addpacket && + imsg_add(obuf, pkt.pkt_buf, pkt.pkt_len) == -1) + goto done; + + /* Set output header */ + memcpy(oh, ih, sizeof(*oh)); + oh->oh_length = htons(ibuf_length(obuf)); + oh->oh_type = addflow ? OFP_T_FLOW_MOD : OFP_T_PACKET_OUT; + oh->oh_xid = htonl(con->con_xidnxt++); + + ofp13_debug(sc, &con->con_local, &con->con_peer, oh, obuf); + + ofp_send(con, NULL, obuf); + + if (addflow && addpacket) { + /* loop to output the packet again */ + addflow = 0; + if ((obuf = ibuf_static()) == NULL) + goto done; + goto again; + } + + ret = 0; + done: + ibuf_release(obuf); + return (ret); +#else + return (0); +#endif +} diff --git a/usr.sbin/switchd/ofp_map.h b/usr.sbin/switchd/ofp_map.h index 3f2fe51f0bb..a9613abd6e0 100644 --- a/usr.sbin/switchd/ofp_map.h +++ b/usr.sbin/switchd/ofp_map.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ofp_map.h,v 1.1 2016/07/19 16:54:26 reyk Exp $ */ +/* $OpenBSD: ofp_map.h,v 1.2 2016/07/20 14:15:08 reyk Exp $ */ /* * Copyright (c) 2013-2016 Reyk Floeter @@ -38,6 +38,7 @@ extern struct constmap ofp10_errflowmod_map[]; extern struct constmap ofp_v_map[]; extern struct constmap ofp_t_map[]; extern struct constmap ofp_hi_map[]; +extern struct constmap ofp_pktin_map[]; extern struct constmap ofp_port_map[]; extern struct constmap ofp_config_map[]; extern struct constmap ofp_portstate_map[]; diff --git a/usr.sbin/switchd/switchd.h b/usr.sbin/switchd/switchd.h index 93e8da604fa..be5c5ef6d41 100644 --- a/usr.sbin/switchd/switchd.h +++ b/usr.sbin/switchd/switchd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: switchd.h,v 1.2 2016/07/20 11:43:31 jsg Exp $ */ +/* $OpenBSD: switchd.h,v 1.3 2016/07/20 14:15:08 reyk Exp $ */ /* * Copyright (c) 2013-2016 Reyk Floeter @@ -186,9 +186,6 @@ void ofp_accept(int, short, void *); /* ofp10.c */ int ofp10_hello(struct switchd *, struct switch_connection *, struct ofp_header *, struct ibuf *); -void ofp10_debug_header(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *); void ofp10_debug(struct switchd *, struct sockaddr_storage *, struct sockaddr_storage *, struct ofp_header *, struct ibuf *); @@ -196,9 +193,6 @@ int ofp10_input(struct switchd *, struct switch_connection *, struct ofp_header *, struct ibuf *); /* ofp13.c */ -void ofp13_debug(struct switchd *, - struct sockaddr_storage *, struct sockaddr_storage *, - struct ofp_header *, struct ibuf *); int ofp13_input(struct switchd *, struct switch_connection *, struct ofp_header *, struct ibuf *);