Learn remote switch's flow table properties so we can use this information
to decide where to install the default table-miss flow for OpenFlow 1.3.
This is not needed by OpenFlow 1.0 since it already does this by default.

This diff implements the functions to ask the remote switch for tables
information and to parse them into data structures that we can use to
decide where can the switchd(8) install flows and what kind. After the
tables information are parsed and stored we use that to select the first
table with the capabilies we need to send packets to controller.

Even though this is already enough to make switchd(8) to work with
switchd(4) and HP 3800 by default, it doesn't consider the possibility
of having installed flows that changes the normal table processing. So
the next implementation step is to obtain flow information for all table
and make switchd(8) also consider this when choosing the table.

ok?

Index: usr.sbin/switchd/ofp.c
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/ofp.c,v
retrieving revision 1.17
diff -u -p -r1.17 ofp.c
--- usr.sbin/switchd/ofp.c      2 Dec 2016 14:39:46 -0000       1.17
+++ usr.sbin/switchd/ofp.c      2 Dec 2016 15:03:51 -0000
@@ -231,14 +231,11 @@ ofp_nextstate(struct switchd *sc, struct
                /* Let's not ask this while we don't use it. */
                ofp13_flow_stats(sc, con, OFP_PORT_ANY, OFP_GROUP_ID_ANY,
                    OFP_TABLE_ID_ALL);
-               ofp13_table_features(sc, con, 0);
                ofp13_desc(sc, con);
 #endif
+               rv |= ofp13_table_features(sc, con, 0);
                rv |= ofp13_setconfig(sc, con, OFP_CONFIG_FRAG_NORMAL,
                    OFP_CONTROLLER_MAXLEN_NO_BUFFER);
-
-               /* Use table '0' for switch(4) and '100' for HP 3800. */
-               rv |= ofp13_tablemiss_sendctrl(sc, con, 0);
                break;
 
 
Index: usr.sbin/switchd/ofp13.c
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/ofp13.c,v
retrieving revision 1.41
diff -u -p -r1.41 ofp13.c
--- usr.sbin/switchd/ofp13.c    2 Dec 2016 14:39:46 -0000       1.41
+++ usr.sbin/switchd/ofp13.c    2 Dec 2016 15:03:52 -0000
@@ -70,10 +70,8 @@ int   ofp13_packet_in(struct switchd *, s
            struct ofp_header *, struct ibuf *);
 int     ofp13_flow_removed(struct switchd *, struct switch_connection *,
            struct ofp_header *, struct ibuf *);
-int     ofp13_parse_instruction(struct ibuf *, struct ofp_instruction *);
-int     ofp13_parse_action(struct ibuf *, struct ofp_action_header *);
-int     ofp13_parse_oxm(struct ibuf *, struct ofp_ox_match *);
-int     ofp13_parse_tableproperties(struct ibuf *, struct ofp_table_features 
*);
+int     ofp13_tableproperties(struct switch_connection *, struct ibuf *,
+           off_t, size_t, int);
 int     ofp13_multipart_reply(struct switchd *, struct switch_connection *,
            struct ofp_header *, struct ibuf *);
 int     ofp13_validate_tableproperty(struct ibuf *, off_t, int);
@@ -104,6 +102,9 @@ int  ofp13_setconfig_validate(struct swi
            struct sockaddr_storage *, struct sockaddr_storage *,
            struct ofp_header *, struct ibuf *);
 
+int     ofp13_switchconfigure(struct switchd *, struct switch_connection *);
+int     ofp13_getflowtable(struct switch_connection *);
+
 struct ofp_callback ofp13_callbacks[] = {
        { OFP_T_HELLO,                  ofp13_hello, ofp_validate_hello },
        { OFP_T_ERROR,                  NULL, ofp13_validate_error },
@@ -1013,7 +1014,7 @@ ofp13_packet_in(struct switchd *sc, stru
        struct ofp_ox_match             *oxm;
        struct packet                    pkt;
        struct ibuf                     *obuf = NULL;
-       int                              ret = -1;
+       int                              table, ret = -1;
        ssize_t                          len, mlen;
        uint32_t                         srcport = 0, dstport;
        int                              addflow = 0, sendbuffer = 0;
@@ -1091,6 +1092,13 @@ ofp13_packet_in(struct switchd *sc, stru
 
  again:
        if (addflow) {
+               table = ofp13_getflowtable(con);
+               if (table > OFP_TABLE_ID_MAX || table < 0) {
+                       /* This switch doesn't support installing flows. */
+                       addflow = 0;
+                       goto again;
+               }
+
                if ((fm = ibuf_advance(obuf, sizeof(*fm))) == NULL)
                        goto done;
 
@@ -1101,6 +1109,7 @@ ofp13_packet_in(struct switchd *sc, stru
                fm->fm_hard_timeout = 0; /* permanent */
                fm->fm_priority = 0;
                fm->fm_buffer_id = pin->pin_buffer_id;
+               fm->fm_table_id = table;
                fm->fm_flags = htons(OFP_FLOWFLAG_SEND_FLOW_REMOVED);
                if (pin->pin_buffer_id == htonl(OFP_PKTOUT_NO_BUFFER))
                        sendbuffer = 1;
@@ -1191,83 +1200,50 @@ ofp13_flow_removed(struct switchd *sc, s
 }
 
 int
-ofp13_parse_instruction(struct ibuf *ibuf, struct ofp_instruction *i)
-{
-       int                      type;
-       int                      len;
-
-       type = ntohs(i->i_type);
-       len = ntohs(i->i_len);
-
-       log_debug("\t\t%s", print_map(type, ofp_instruction_t_map));
-
-       return (len);
-}
-
-int
-ofp13_parse_action(struct ibuf *ibuf, struct ofp_action_header *ah)
-{
-       int                              len, type;
-
-       len = htons(ah->ah_len);
-       type = htons(ah->ah_type);
-
-       log_debug("\t\t%s", print_map(type, ofp_action_map));
-
-       return (len);
-}
-
-int
-ofp13_parse_oxm(struct ibuf *ibuf, struct ofp_ox_match *oxm)
+ofp13_tableproperties(struct switch_connection *con, struct ibuf *ibuf,
+    off_t off, size_t total, int new)
 {
-       int                     length, type, class, hasmask;
+       struct ofp_table_features               *tf;
+       struct ofp_table_feature_property       *tp;
+       struct ofp_instruction                  *i;
+       struct ofp_action_header                *ah;
+       struct ofp_ox_match                     *oxm;
+       struct switch_table                     *st;
+       uint8_t                                 *next_table;
+       int                                      remaining, type, length;
+       int                                      hlen, padsize;
+       int                                      class, dtype, dlen;
 
-       class = ntohs(oxm->oxm_class);
-       type = OFP_OXM_GET_FIELD(oxm);
-       hasmask = OFP_OXM_GET_HASMASK(oxm);
        /*
-        * XXX the OpenFlow 1.3.5 specification says this field is only
-        * 4 bytes long, however the experimental type is 8 bytes.
+        * This is a new table features reply, free our previous tables
+        * to get the updated ones.
         */
-       length = sizeof(*oxm);
+       if (new)
+               switch_freetables(con);
 
-       log_debug("\t\t%s hasmask %s type %s",
-           print_map(class, ofp_oxm_c_map), hasmask ? "yes" : "no",
-           print_map(type, ofp_xm_t_map));
+ next_table:
+       if ((tf = ibuf_seek(ibuf, off, sizeof(*tf))) == NULL)
+               return (-1);
 
-       if (class == OFP_OXM_C_OPENFLOW_EXPERIMENTER) {
-               /* Get the last bytes. */
-               if (ibuf_getdata(ibuf, 4) == NULL)
-                       return (-1);
+       hlen = htons(tf->tf_length);
+       total -= hlen;
+       remaining = hlen - sizeof(*tf);
+       off += sizeof(*tf);
 
-               return (8);
+       st = switch_tablelookup(con, tf->tf_tableid);
+       if (st == NULL) {
+               st = switch_newtable(con, tf->tf_tableid);
+               if (st == NULL)
+                       return (-1);
        }
 
-       return (length);
-}
-
-int
-ofp13_parse_tableproperties(struct ibuf *ibuf, struct ofp_table_features *tf)
-{
-       struct ofp_table_feature_property       *tp;
-       struct ofp_instruction                  *i;
-       struct ofp_action_header                *ah;
-       struct ofp_ox_match                     *oxm;
-       uint8_t                                 *next_table;
-       int                                      remaining, type, length;
-       int                                      totallen, padsize, rv;
-
-       log_debug("Table %s (%d) max_entries %u config %u "
-           "metadata match %#016llx write %#016llx",
-           tf->tf_name, tf->tf_tableid, ntohl(tf->tf_max_entries),
-           ntohl(tf->tf_config), be64toh(tf->tf_metadata_match),
-           be64toh(tf->tf_metadata_write));
-       totallen = htons(tf->tf_length);
-       remaining = totallen - sizeof(*tf);
+       st->st_maxentries = ntohl(tf->tf_max_entries);
 
  next_table_property:
-       if ((tp = ibuf_getdata(ibuf, sizeof(*tp))) == NULL)
+       if ((tp = ibuf_seek(ibuf, off, sizeof(*tp))) == NULL) {
+               switch_deltable(con, st);
                return (-1);
+       }
 
        type = ntohs(tp->tp_type);
        length = ntohs(tp->tp_length);
@@ -1276,32 +1252,63 @@ ofp13_parse_tableproperties(struct ibuf 
        padsize = OFP_ALIGN(length) - length;
        remaining -= OFP_ALIGN(length);
        length -= sizeof(*tp);
-
-       log_debug("\t%s:", print_map(type, ofp_table_featprop_map));
-       if (length == 0)
-               log_debug("\t\tNONE");
+       off += sizeof(*tp);
 
        switch (type) {
        case OFP_TABLE_FEATPROP_INSTRUCTION:
        case OFP_TABLE_FEATPROP_INSTRUCTION_MISS:
+               if (type == OFP_TABLE_FEATPROP_INSTRUCTION)
+                       st->st_instructions = 0;
+               else
+                       st->st_instructionsmiss = 0;
+
                while (length) {
-                       if ((i = ibuf_getdata(ibuf, sizeof(*i))) == NULL)
-                               return (-1);
-                       if ((rv = ofp13_parse_instruction(ibuf, i)) == -1)
+                       if ((i = ibuf_seek(ibuf, off, sizeof(*i))) == NULL) {
+                               switch_deltable(con, st);
                                return (-1);
-                       length -= rv;
+                       }
+
+                       dtype = ntohs(i->i_type);
+                       dlen = ntohs(i->i_len);
+                       if (type == OFP_TABLE_FEATPROP_INSTRUCTION)
+                               st->st_instructions |= 1ULL << dtype;
+                       else
+                               st->st_instructionsmiss |= 1ULL << dtype;
+
+                       if (dtype == OFP_INSTRUCTION_T_EXPERIMENTER) {
+                               length -= dlen;
+                               off += dlen;
+                       } else {
+                               length -= sizeof(*i);
+                               off += sizeof(*i);
+                       }
                }
                break;
 
        case OFP_TABLE_FEATPROP_NEXT_TABLES:
        case OFP_TABLE_FEATPROP_NEXT_TABLES_MISS:
+               if (type == OFP_TABLE_FEATPROP_NEXT_TABLES)
+                       memset(st->st_nexttable, 0, sizeof(st->st_nexttable));
+               else
+                       memset(st->st_nexttablemiss, 0,
+                           sizeof(st->st_nexttablemiss));
+
                while (length) {
-                       if ((next_table = ibuf_getdata(ibuf,
-                           sizeof(*next_table))) == NULL)
+                       if ((next_table = ibuf_seek(ibuf, off,
+                           sizeof(*next_table))) == NULL) {
+                               switch_deltable(con, st);
                                return (-1);
+                       }
+
+                       if (type == OFP_TABLE_FEATPROP_NEXT_TABLES)
+                               st->st_nexttable[(*next_table) / 64] |=
+                                   1ULL << ((*next_table) % 64);
+                       else
+                               st->st_nexttablemiss[(*next_table) / 64] |=
+                                   1ULL << ((*next_table) % 64);
 
-                       log_debug("\t\t%d", *next_table);
                        length -= sizeof(*next_table);
+                       off += sizeof(*next_table);
                }
                break;
 
@@ -1309,16 +1316,37 @@ ofp13_parse_tableproperties(struct ibuf 
        case OFP_TABLE_FEATPROP_WRITE_ACTIONS_MISS:
        case OFP_TABLE_FEATPROP_APPLY_ACTIONS:
        case OFP_TABLE_FEATPROP_APPLY_ACTIONS_MISS:
+               if (type == OFP_TABLE_FEATPROP_WRITE_ACTIONS ||
+                   type == OFP_TABLE_FEATPROP_APPLY_ACTIONS)
+                       st->st_actions = 0;
+               else
+                       st->st_actionsmiss = 0;
+
                while (length) {
                        /*
-                        * XXX the OpenFlow 1.3.5 specs says that we only
-                        * get 4 bytes here instead of the full OXM.
+                        * NOTE the OpenFlow 1.3.5 specs says that we only
+                        * get 4 bytes here instead of the full action header.
                         */
-                       if ((ah = ibuf_getdata(ibuf, 4)) == NULL)
-                               return (-1);
-                       if ((rv = ofp13_parse_action(ibuf, ah)) == -1)
+                       if ((ah = ibuf_seek(ibuf, off, 4)) == NULL) {
+                               switch_deltable(con, st);
                                return (-1);
-                       length -= rv;
+                       }
+
+                       dtype = ntohs(ah->ah_type);
+                       dlen = ntohs(ah->ah_len);
+                       if (type == OFP_TABLE_FEATPROP_WRITE_ACTIONS ||
+                           type == OFP_TABLE_FEATPROP_APPLY_ACTIONS)
+                               st->st_actions |= 1ULL << dtype;
+                       else
+                               st->st_actionsmiss |= 1ULL << dtype;
+
+                       if (dtype == OFP_ACTION_EXPERIMENTER) {
+                               length -= dlen;
+                               off += dlen;
+                       } else {
+                               length -= 4;
+                               off += 4;
+                       }
                }
                break;
 
@@ -1328,32 +1356,72 @@ ofp13_parse_tableproperties(struct ibuf 
        case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS:
        case OFP_TABLE_FEATPROP_APPLY_SETFIELD:
        case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS:
+               if (type == OFP_TABLE_FEATPROP_WRITE_SETFIELD ||
+                   type == OFP_TABLE_FEATPROP_APPLY_SETFIELD)
+                       st->st_setfield = 0;
+               else if (type == OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS ||
+                       type == OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS)
+                       st->st_setfieldmiss = 0;
+               else if (type == OFP_TABLE_FEATPROP_MATCH)
+                       st->st_match = 0;
+               else
+                       st->st_wildcard = 0;
+
                while (length) {
-                       if ((oxm = ibuf_getdata(ibuf, sizeof(*oxm))) == NULL)
-                               return (-1);
-                       if ((rv = ofp13_parse_oxm(ibuf, oxm)) == -1)
+                       if ((oxm = ibuf_seek(ibuf, off,
+                           sizeof(*oxm))) == NULL) {
+                               switch_deltable(con, st);
                                return (-1);
-                       length -= rv;
-               }
-               break;
+                       }
 
-       default:
-               log_debug("%s: unsupported property type: %d", __func__, type);
+                       class = ntohs(oxm->oxm_class);
+                       if (class != OFP_OXM_C_OPENFLOW_BASIC) {
+                               if (class == OFP_OXM_C_OPENFLOW_EXPERIMENTER) {
+                                       length -= sizeof(*oxm) + 4;
+                                       off += sizeof(*oxm) + 4;
+                               } else {
+                                       length -= sizeof(*oxm);
+                                       off += sizeof(*oxm);
+                               }
+                               continue;
+                       }
 
-               /* Skip this field and try to continue otherwise fail. */
-               if (ibuf_getdata(ibuf, length) == NULL)
-                       return (-1);
+                       dtype = OFP_OXM_GET_FIELD(oxm);
+                       if (type == OFP_TABLE_FEATPROP_WRITE_SETFIELD ||
+                           type == OFP_TABLE_FEATPROP_APPLY_SETFIELD)
+                               st->st_setfield |= 1ULL << dtype;
+                       else if
+                           (type == OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS ||
+                           type == OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS)
+                               st->st_setfieldmiss |= 1ULL << dtype;
+                       else if (type == OFP_TABLE_FEATPROP_MATCH)
+                               st->st_match |= 1ULL << dtype;
+                       else
+                               st->st_wildcard |= 1ULL << dtype;
 
+                       length -= sizeof(*oxm);
+                       off += sizeof(*oxm);
+               }
                break;
-       }
 
-       /* Skip the padding and read the next property if any. */
-       if (padsize && ibuf_getdata(ibuf, padsize) == NULL)
+       case OFP_TABLE_FEATPROP_EXPERIMENTER:
+       case OFP_TABLE_FEATPROP_EXPERIMENTER_MISS:
+               off += length;
+               break;
+
+       default:
+               log_debug("Unsupported table property %d", type);
                return (-1);
-       if (remaining)
+       }
+
+       if (padsize)
+               off += padsize;
+       if (remaining > 0)
                goto next_table_property;
+       if (total > 0)
+               goto next_table;
 
-       return (totallen);
+       return (0);
 }
 
 int
@@ -1361,18 +1429,25 @@ ofp13_multipart_reply(struct switchd *sc
     struct ofp_header *oh, struct ibuf *ibuf)
 {
        struct ofp_multipart            *mp;
-       struct ofp_table_features       *tf;
-       int                              readlen, type, flags;
+       int                              type, flags, more, new = 0;
        int                              remaining;
+       off_t                            off;
 
-       if ((mp = ibuf_getdata(ibuf, sizeof(*mp))) == NULL)
+       off = 0;
+       if ((mp = ibuf_seek(ibuf, 0, sizeof(*mp))) == NULL)
                return (-1);
 
        type = ntohs(mp->mp_type);
        flags = ntohs(mp->mp_flags);
        remaining = ntohs(oh->oh_length) - sizeof(*mp);
+       off += sizeof(*mp);
+
+       more = (flags & OFP_MP_FLAG_REPLY_MORE) == OFP_MP_FLAG_REPLY_MORE;
+       /* Signalize new requests. */
+       if (ofp_multipart_lookup(con, oh->oh_xid) == NULL)
+               new = 1;
 
-       if (flags & OFP_MP_FLAG_REPLY_MORE) {
+       if (more) {
                if (ofp_multipart_add(con, oh->oh_xid, type) == -1) {
                        ofp13_error(sc, con, oh, ibuf,
                            OFP_ERRTYPE_BAD_REQUEST,
@@ -1393,15 +1468,12 @@ ofp13_multipart_reply(struct switchd *sc
 
        switch (type) {
        case OFP_MP_T_TABLE_FEATURES:
- read_next_table:
-               if ((tf = ibuf_getdata(ibuf, sizeof(*tf))) == NULL)
-                       return (-1);
-               if ((readlen = ofp13_parse_tableproperties(ibuf, tf)) == -1)
+               if (ofp13_tableproperties(con, ibuf, off, remaining, new))
                        return (-1);
 
-               remaining -= readlen;
-               if (remaining)
-                       goto read_next_table;
+               /* We finished receiving tables, configure the switch. */
+               if (more == 0)
+                       return (ofp13_switchconfigure(sc, con));
                break;
        }
 
@@ -2136,4 +2208,49 @@ ofp13_tablemiss_sendctrl(struct switchd 
  err:
        (void)oflowmod_err(&ctx, __func__, __LINE__);
        return (-1);
+}
+
+int
+ofp13_switchconfigure(struct switchd *sc, struct switch_connection *con)
+{
+       struct switch_table             *st;
+
+       /* Look for a table with 'apply' and 'output' support for miss. */
+       TAILQ_FOREACH(st, &con->con_stlist, st_entry) {
+               if ((st->st_instructionsmiss &
+                   (1ULL << OFP_INSTRUCTION_T_APPLY_ACTIONS)) == 0)
+                       continue;
+               if ((st->st_actionsmiss & (1ULL << OFP_ACTION_OUTPUT)) == 0)
+                       continue;
+
+               break;
+       }
+       if (st == NULL) {
+               log_warn("No apply output for this switch");
+               return (-1);
+       }
+
+       /* Install the flow to receive packets from the switch. */
+       return (ofp13_tablemiss_sendctrl(sc, con, st->st_table));
+}
+
+int
+ofp13_getflowtable(struct switch_connection *con)
+{
+       struct switch_table             *st;
+
+       /* Look for a table with 'apply' and 'output' support. */
+       TAILQ_FOREACH(st, &con->con_stlist, st_entry) {
+               if ((st->st_instructions &
+                   (1ULL << OFP_INSTRUCTION_T_APPLY_ACTIONS)) == 0)
+                       continue;
+               if ((st->st_actions & (1ULL << OFP_ACTION_OUTPUT)) == 0)
+                       continue;
+
+               break;
+       }
+       if (st == NULL)
+               return (-1);
+
+       return (st->st_table);
 }
Index: usr.sbin/switchd/ofp_common.c
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/ofp_common.c,v
retrieving revision 1.9
diff -u -p -r1.9 ofp_common.c
--- usr.sbin/switchd/ofp_common.c       2 Dec 2016 14:39:46 -0000       1.9
+++ usr.sbin/switchd/ofp_common.c       2 Dec 2016 15:03:52 -0000
@@ -1115,15 +1115,31 @@ ofp_instruction(struct ibuf *ibuf, uint1
        return (oi);
 }
 
-int
-ofp_multipart_add(struct switch_connection *con, uint32_t xid, uint8_t type)
+struct multipart_message *
+ofp_multipart_lookup(struct switch_connection *con, uint32_t xid)
 {
        struct multipart_message        *mm;
 
-       /* A multipart reply have the same xid and type in all parts. */
        SLIST_FOREACH(mm, &con->con_mmlist, mm_entry) {
                if (mm->mm_xid != xid)
                        continue;
+
+               return (mm);
+       }
+
+       return (NULL);
+}
+
+int
+ofp_multipart_add(struct switch_connection *con, uint32_t xid, uint8_t type)
+{
+       struct multipart_message        *mm;
+
+       if ((mm = ofp_multipart_lookup(con, xid)) != NULL) {
+               /*
+                * A multipart reply has the same xid and type, otherwise
+                * something went wrong.
+                */
                if (mm->mm_type != type)
                        return (-1);
 
@@ -1170,6 +1186,51 @@ ofp_multipart_clear(struct switch_connec
        while (!SLIST_EMPTY(&con->con_mmlist)) {
                mm = SLIST_FIRST(&con->con_mmlist);
                ofp_multipart_free(con, mm);
+       }
+}
+
+struct switch_table *
+switch_tablelookup(struct switch_connection *con, int table)
+{
+       struct switch_table             *st;
+
+       TAILQ_FOREACH(st, &con->con_stlist, st_entry) {
+               if (st->st_table == table)
+                       return (st);
+       }
+
+       return (NULL);
+}
+
+struct switch_table *
+switch_newtable(struct switch_connection *con, int table)
+{
+       struct switch_table             *st;
+
+       if ((st = calloc(1, sizeof(*st))) == NULL)
+               return (NULL);
+
+       st->st_table = table;
+       TAILQ_INSERT_TAIL(&con->con_stlist, st, st_entry);
+
+       return (st);
+}
+
+void
+switch_deltable(struct switch_connection *con, struct switch_table *st)
+{
+       TAILQ_REMOVE(&con->con_stlist, st, st_entry);
+       free(st);
+}
+
+void
+switch_freetables(struct switch_connection *con)
+{
+       struct switch_table             *st;
+
+       while (!TAILQ_EMPTY(&con->con_stlist)) {
+               st = TAILQ_FIRST(&con->con_stlist);
+               switch_deltable(con, st);
        }
 }
 
Index: usr.sbin/switchd/ofrelay.c
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/ofrelay.c,v
retrieving revision 1.9
diff -u -p -r1.9 ofrelay.c
--- usr.sbin/switchd/ofrelay.c  2 Dec 2016 14:39:46 -0000       1.9
+++ usr.sbin/switchd/ofrelay.c  2 Dec 2016 15:03:52 -0000
@@ -98,6 +98,7 @@ ofrelay_close(struct switch_connection *
        TAILQ_REMOVE(&sc->sc_conns, con, con_entry);
        ofrelay_sessions--;
 
+       switch_freetables(con);
        ofp_multipart_clear(con);
        switch_remove(con->con_sc, con->con_switch);
        msgbuf_clear(&con->con_wbuf);
@@ -405,6 +406,7 @@ ofrelay_attach(struct switch_server *srv
        con->con_srv = srv;
        con->con_state = OFP_STATE_CLOSED;
        SLIST_INIT(&con->con_mmlist);
+       TAILQ_INIT(&con->con_stlist);
 
        memcpy(&con->con_peer, sa, sa->sa_len);
        con->con_port = htons(socket_getport(&con->con_peer));
Index: usr.sbin/switchd/switchd.h
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/switchd.h,v
retrieving revision 1.27
diff -u -p -r1.27 switchd.h
--- usr.sbin/switchd/switchd.h  2 Dec 2016 14:39:46 -0000       1.27
+++ usr.sbin/switchd/switchd.h  2 Dec 2016 15:03:52 -0000
@@ -68,6 +68,30 @@ struct switch_control {
 };
 RB_HEAD(switch_head, switch_control);
 
+struct switch_table {
+       TAILQ_ENTRY(switch_table)        st_entry;
+
+       int                              st_table;
+       unsigned int                     st_entries;
+       unsigned int                     st_maxentries;
+
+       uint32_t                         st_actions;
+       uint32_t                         st_actionsmiss;
+
+       uint32_t                         st_instructions;
+       uint32_t                         st_instructionsmiss;
+
+       uint64_t                         st_setfield;
+       uint64_t                         st_setfieldmiss;
+       uint64_t                         st_match;
+       uint64_t                         st_wildcard;
+
+       /* Maximum of 256 tables (64 * 4). */
+       uint64_t                         st_nexttable[4];
+       uint64_t                         st_nexttablemiss[4];
+};
+TAILQ_HEAD(switch_table_list, switch_table);
+
 struct multipart_message {
        SLIST_ENTRY(multipart_message)
                                 mm_entry;
@@ -105,6 +129,8 @@ struct switch_connection {
        struct switch_server    *con_srv;
 
        struct multipart_list    con_mmlist;
+       struct switch_table_list
+                                con_stlist;
 
        TAILQ_ENTRY(switch_connection)
                                 con_entry;
@@ -247,6 +273,13 @@ void                ofp_accept(int, short, void *);
 int             ofp_input(struct switch_connection *, struct ibuf *);
 int             ofp_nextstate(struct switchd *, struct switch_connection *,
                    enum ofp_state);
+struct switch_table *
+                switch_tablelookup(struct switch_connection *, int);
+struct switch_table *
+                switch_newtable(struct switch_connection *, int);
+void            switch_deltable(struct switch_connection *,
+                   struct switch_table *);
+void            switch_freetables(struct switch_connection *);
 
 /* ofp10.c */
 int             ofp10_hello(struct switchd *, struct switch_connection *,
@@ -289,6 +322,8 @@ int          ofp_validate(struct switchd *,
                    struct ofp_header *, struct ibuf *, uint8_t);
 int             ofp_output(struct switch_connection *, struct ofp_header *,
                    struct ibuf *);
+struct multipart_message *
+                   ofp_multipart_lookup(struct switch_connection *, uint32_t);
 int             ofp_multipart_add(struct switch_connection *, uint32_t,
                    uint8_t);
 void            ofp_multipart_del(struct switch_connection *, uint32_t);
@@ -364,7 +399,6 @@ int          ofp_send_hello(struct switchd *, s
                    int);
 int             ofp_send_featuresrequest(struct switchd *,
                    struct switch_connection *);
-
 /* ofcconn.c */
 void            ofcconn(struct privsep *, struct privsep_proc *);
 void            ofcconn_shutdown(void);

Reply via email to