Update OpenFlow 1.3 stub based on the 1.0 code.
authorreyk <reyk@openbsd.org>
Wed, 20 Jul 2016 14:15:08 +0000 (14:15 +0000)
committerreyk <reyk@openbsd.org>
Wed, 20 Jul 2016 14:15:08 +0000 (14:15 +0000)
usr.sbin/switchd/ofp.c
usr.sbin/switchd/ofp10.c
usr.sbin/switchd/ofp13.c
usr.sbin/switchd/ofp_map.h
usr.sbin/switchd/switchd.h

index eeb7235..8b8778f 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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);
 }
index bd89686..d76249c 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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 *);
index 0747d92..8c850a5 100644 (file)
@@ -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 <reyk@openbsd.org>
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* XXX not implemented, this is just a stub */
-
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/socket.h>
 
+#include <net/if.h>
+#include <net/if_arp.h>
 #include <netinet/in.h>
+#include <netinet/if_ether.h>
 #include <netinet/tcp.h>
 
 #include <stdio.h>
 #include <event.h>
 
 #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
+}
index 3f2fe51..a9613ab 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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[];
index 93e8da6..be5c5ef 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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 *);