Abstract everything that uses ofp_phy_port, add OF1.1 support.
authorBen Pfaff <blp@nicira.com>
Thu, 16 Feb 2012 00:33:04 +0000 (16:33 -0800)
committerBen Pfaff <blp@nicira.com>
Wed, 7 Mar 2012 22:05:11 +0000 (14:05 -0800)
Reviewed-by: Simon Horman <horms@verge.net.au>
Signed-off-by: Ben Pfaff <blp@nicira.com>
16 files changed:
include/openflow/openflow-1.0.h
include/openflow/openflow-1.1.h
include/openflow/openflow-common.h
lib/learning-switch.c
lib/ofp-errors.h
lib/ofp-print.c
lib/ofp-util.c
lib/ofp-util.h
ofproto/connmgr.c
ofproto/connmgr.h
ofproto/ofproto-dpif.c
ofproto/ofproto-provider.h
ofproto/ofproto.c
tests/ofp-print.at
tests/ofproto.at
utilities/ovs-ofctl.c

index bca1067..5844a96 100644 (file)
@@ -64,17 +64,6 @@ enum ofp10_type {
     OFPT10_QUEUE_GET_CONFIG_REPLY     /* Controller/switch message */
 };
 
-/* Header on all OpenFlow packets. */
-struct ofp_header {
-    uint8_t version;    /* An OpenFlow version number, e.g. OFP10_VERSION. */
-    uint8_t type;       /* One of the OFPT_ constants. */
-    ovs_be16 length;    /* Length including this ofp_header. */
-    ovs_be32 xid;       /* Transaction id associated with this packet.
-                           Replies use the same id as was in the request
-                           to facilitate pairing. */
-};
-OFP_ASSERT(sizeof(struct ofp_header) == 8);
-
 /* OFPT_HELLO.  This message has an empty body, but implementations must
  * ignore any data included in the body, to allow for future extensions. */
 struct ofp_hello {
@@ -105,134 +94,80 @@ struct ofp_switch_config {
 };
 OFP_ASSERT(sizeof(struct ofp_switch_config) == 12);
 
-/* Capabilities supported by the datapath. */
-enum ofp_capabilities {
-    OFPC_FLOW_STATS     = 1 << 0,  /* Flow statistics. */
-    OFPC_TABLE_STATS    = 1 << 1,  /* Table statistics. */
-    OFPC_PORT_STATS     = 1 << 2,  /* Port statistics. */
-    OFPC_STP            = 1 << 3,  /* 802.1d spanning tree. */
-    OFPC_RESERVED       = 1 << 4,  /* Reserved, must not be set. */
-    OFPC_IP_REASM       = 1 << 5,  /* Can reassemble IP fragments. */
-    OFPC_QUEUE_STATS    = 1 << 6,  /* Queue statistics. */
-    OFPC_ARP_MATCH_IP   = 1 << 7   /* Match IP addresses in ARP
-                                      pkts. */
-};
-
-/* Flags to indicate behavior of the physical port.  These flags are
- * used in ofp_phy_port to describe the current configuration.  They are
- * used in the ofp_port_mod message to configure the port's behavior.
- */
-enum ofp_port_config {
-    OFPPC_PORT_DOWN    = 1 << 0,  /* Port is administratively down. */
-
-    OFPPC_NO_STP       = 1 << 1,  /* Disable 802.1D spanning tree on port. */
-    OFPPC_NO_RECV      = 1 << 2,  /* Drop all packets except 802.1D
-                                     spanning tree packets. */
-    OFPPC_NO_RECV_STP  = 1 << 3,  /* Drop received 802.1D STP packets. */
-    OFPPC_NO_FLOOD     = 1 << 4,  /* Do not include this port when flooding. */
-    OFPPC_NO_FWD       = 1 << 5,  /* Drop packets forwarded to port. */
-    OFPPC_NO_PACKET_IN = 1 << 6   /* Do not send packet-in msgs for port. */
+/* OpenFlow 1.0 specific capabilities supported by the datapath (struct
+ * ofp_switch_features, member capabilities). */
+enum ofp10_capabilities {
+    OFPC10_STP            = 1 << 3,  /* 802.1d spanning tree. */
+    OFPC10_RESERVED       = 1 << 4,  /* Reserved, must not be set. */
 };
 
-/* Current state of the physical port.  These are not configurable from
- * the controller.
+/* OpenFlow 1.0 specific flags to indicate behavior of the physical port.
+ * These flags are used in ofp10_phy_port to describe the current
+ * configuration.  They are used in the ofp10_port_mod message to configure the
+ * port's behavior.
  */
-enum ofp_port_state {
-    OFPPS_LINK_DOWN   = 1 << 0, /* No physical link present. */
+enum ofp10_port_config {
+    OFPPC10_NO_STP       = 1 << 1, /* Disable 802.1D spanning tree on port. */
+    OFPPC10_NO_RECV_STP  = 1 << 3, /* Drop received 802.1D STP packets. */
+    OFPPC10_NO_FLOOD     = 1 << 4, /* Do not include port when flooding. */
+#define OFPPC10_ALL (OFPPC_PORT_DOWN | OFPPC10_NO_STP | OFPPC_NO_RECV | \
+                     OFPPC10_NO_RECV_STP | OFPPC10_NO_FLOOD | OFPPC_NO_FWD | \
+                     OFPPC_NO_PACKET_IN)
+};
 
-    /* The OFPPS_STP_* bits have no effect on switch operation.  The
+/* OpenFlow 1.0 specific current state of the physical port.  These are not
+ * configurable from the controller.
+ */
+enum ofp10_port_state {
+    /* The OFPPS10_STP_* bits have no effect on switch operation.  The
      * controller must adjust OFPPC_NO_RECV, OFPPC_NO_FWD, and
      * OFPPC_NO_PACKET_IN appropriately to fully implement an 802.1D spanning
      * tree. */
-    OFPPS_STP_LISTEN  = 0 << 8, /* Not learning or relaying frames. */
-    OFPPS_STP_LEARN   = 1 << 8, /* Learning but not relaying frames. */
-    OFPPS_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */
-    OFPPS_STP_BLOCK   = 3 << 8, /* Not part of spanning tree. */
-    OFPPS_STP_MASK    = 3 << 8  /* Bit mask for OFPPS_STP_* values. */
-};
-
-/* Features of physical ports available in a datapath. */
-enum ofp_port_features {
-    OFPPF_10MB_HD    = 1 << 0,  /* 10 Mb half-duplex rate support. */
-    OFPPF_10MB_FD    = 1 << 1,  /* 10 Mb full-duplex rate support. */
-    OFPPF_100MB_HD   = 1 << 2,  /* 100 Mb half-duplex rate support. */
-    OFPPF_100MB_FD   = 1 << 3,  /* 100 Mb full-duplex rate support. */
-    OFPPF_1GB_HD     = 1 << 4,  /* 1 Gb half-duplex rate support. */
-    OFPPF_1GB_FD     = 1 << 5,  /* 1 Gb full-duplex rate support. */
-    OFPPF_10GB_FD    = 1 << 6,  /* 10 Gb full-duplex rate support. */
-    OFPPF_COPPER     = 1 << 7,  /* Copper medium. */
-    OFPPF_FIBER      = 1 << 8,  /* Fiber medium. */
-    OFPPF_AUTONEG    = 1 << 9,  /* Auto-negotiation. */
-    OFPPF_PAUSE      = 1 << 10, /* Pause. */
-    OFPPF_PAUSE_ASYM = 1 << 11  /* Asymmetric pause. */
+    OFPPS10_STP_LISTEN  = 0 << 8, /* Not learning or relaying frames. */
+    OFPPS10_STP_LEARN   = 1 << 8, /* Learning but not relaying frames. */
+    OFPPS10_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */
+    OFPPS10_STP_BLOCK   = 3 << 8, /* Not part of spanning tree. */
+    OFPPS10_STP_MASK    = 3 << 8  /* Bit mask for OFPPS10_STP_* values. */
+
+#define OFPPS10_ALL (OFPPS_LINK_DOWN | OFPPS10_STP_MASK)
+};
+
+/* OpenFlow 1.0 specific features of physical ports available in a datapath. */
+enum ofp10_port_features {
+    OFPPF10_COPPER     = 1 << 7,  /* Copper medium. */
+    OFPPF10_FIBER      = 1 << 8,  /* Fiber medium. */
+    OFPPF10_AUTONEG    = 1 << 9,  /* Auto-negotiation. */
+    OFPPF10_PAUSE      = 1 << 10, /* Pause. */
+    OFPPF10_PAUSE_ASYM = 1 << 11  /* Asymmetric pause. */
 };
 
 /* Description of a physical port */
-struct ofp_phy_port {
+struct ofp10_phy_port {
     ovs_be16 port_no;
     uint8_t hw_addr[OFP_ETH_ALEN];
     char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */
 
-    ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
-    ovs_be32 state;         /* Bitmap of OFPPS_* flags. */
+    ovs_be32 config;        /* Bitmap of OFPPC_* and OFPPC10_* flags. */
+    ovs_be32 state;         /* Bitmap of OFPPS_* and OFPPS10_* flags. */
 
-    /* Bitmaps of OFPPF_* that describe features.  All bits zeroed if
-     * unsupported or unavailable. */
+    /* Bitmaps of OFPPF_* and OFPPF10_* that describe features.  All bits
+     * zeroed if unsupported or unavailable. */
     ovs_be32 curr;          /* Current features. */
     ovs_be32 advertised;    /* Features being advertised by the port. */
     ovs_be32 supported;     /* Features supported by the port. */
     ovs_be32 peer;          /* Features advertised by peer. */
 };
-OFP_ASSERT(sizeof(struct ofp_phy_port) == 48);
-
-/* Switch features. */
-struct ofp_switch_features {
-    struct ofp_header header;
-    ovs_be64 datapath_id;   /* Datapath unique ID.  The lower 48-bits are for
-                               a MAC address, while the upper 16-bits are
-                               implementer-defined. */
-
-    ovs_be32 n_buffers;     /* Max packets buffered at once. */
-
-    uint8_t n_tables;       /* Number of tables supported by datapath. */
-    uint8_t pad[3];         /* Align to 64-bits. */
-
-    /* Features. */
-    ovs_be32 capabilities;  /* Bitmap of support "ofp_capabilities". */
-    ovs_be32 actions;       /* Bitmap of supported "ofp_action_type"s. */
-
-    /* Port info.*/
-    struct ofp_phy_port ports[0];  /* Port definitions.  The number of ports
-                                      is inferred from the length field in
-                                      the header. */
-};
-OFP_ASSERT(sizeof(struct ofp_switch_features) == 32);
-
-/* What changed about the physical port */
-enum ofp_port_reason {
-    OFPPR_ADD,              /* The port was added. */
-    OFPPR_DELETE,           /* The port was removed. */
-    OFPPR_MODIFY            /* Some attribute of the port has changed. */
-};
-
-/* A physical port has changed in the datapath */
-struct ofp_port_status {
-    struct ofp_header header;
-    uint8_t reason;          /* One of OFPPR_*. */
-    uint8_t pad[7];          /* Align to 64-bits. */
-    struct ofp_phy_port desc;
-};
-OFP_ASSERT(sizeof(struct ofp_port_status) == 64);
+OFP_ASSERT(sizeof(struct ofp10_phy_port) == 48);
 
 /* Modify behavior of the physical port */
-struct ofp_port_mod {
+struct ofp10_port_mod {
     struct ofp_header header;
     ovs_be16 port_no;
     uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
                                       configurable.  This is used to
                                       sanity-check the request, so it must
                                       be the same as returned in an
-                                      ofp_phy_port struct. */
+                                      ofp10_phy_port struct. */
 
     ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
     ovs_be32 mask;          /* Bitmap of OFPPC_* flags to be changed. */
@@ -241,7 +176,7 @@ struct ofp_port_mod {
                                bits to prevent any action taking place. */
     uint8_t pad[4];         /* Pad to 64-bits. */
 };
-OFP_ASSERT(sizeof(struct ofp_port_mod) == 32);
+OFP_ASSERT(sizeof(struct ofp10_port_mod) == 32);
 
 /* Why is this packet being sent to the controller? */
 enum ofp_packet_in_reason {
index 0e5c901..d02ece3 100644 (file)
@@ -93,6 +93,82 @@ enum ofp11_type {
     OFPT11_QUEUE_GET_CONFIG_REPLY,    /* Controller/switch message */
 };
 
+/* OpenFlow 1.1 port config flags are just the common flags. */
+#define OFPPC11_ALL \
+    (OFPPC_PORT_DOWN | OFPPC_NO_RECV | OFPPC_NO_FWD | OFPPC_NO_PACKET_IN)
+
+/* OpenFlow 1.1 specific current state of the physical port.  These are not
+ * configurable from the controller.
+ */
+enum ofp11_port_state {
+    OFPPS11_BLOCKED      = 1 << 1,  /* Port is blocked */
+    OFPPS11_LIVE         = 1 << 2,  /* Live for Fast Failover Group. */
+#define OFPPS11_ALL (OFPPS_LINK_DOWN | OFPPS11_BLOCKED | OFPPS11_LIVE)
+};
+
+/* OpenFlow 1.1 specific features of ports available in a datapath. */
+enum ofp11_port_features {
+    OFPPF11_40GB_FD    = 1 << 7,  /* 40 Gb full-duplex rate support. */
+    OFPPF11_100GB_FD   = 1 << 8,  /* 100 Gb full-duplex rate support. */
+    OFPPF11_1TB_FD     = 1 << 9,  /* 1 Tb full-duplex rate support. */
+    OFPPF11_OTHER      = 1 << 10, /* Other rate, not in the list. */
+
+    OFPPF11_COPPER     = 1 << 11, /* Copper medium. */
+    OFPPF11_FIBER      = 1 << 12, /* Fiber medium. */
+    OFPPF11_AUTONEG    = 1 << 13, /* Auto-negotiation. */
+    OFPPF11_PAUSE      = 1 << 14, /* Pause. */
+    OFPPF11_PAUSE_ASYM = 1 << 15  /* Asymmetric pause. */
+#define OFPPF11_ALL ((1 << 16) - 1)
+};
+
+/* Description of a port */
+struct ofp11_port {
+    ovs_be32 port_no;
+    uint8_t pad[4];
+    uint8_t hw_addr[OFP_ETH_ALEN];
+    uint8_t pad2[2];                  /* Align to 64 bits. */
+    char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */
+
+    ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
+    ovs_be32 state;         /* Bitmap of OFPPS_* and OFPPS11_* flags. */
+
+    /* Bitmaps of OFPPF_* and OFPPF11_* that describe features.  All bits
+     * zeroed if unsupported or unavailable. */
+    ovs_be32 curr;          /* Current features. */
+    ovs_be32 advertised;    /* Features being advertised by the port. */
+    ovs_be32 supported;     /* Features supported by the port. */
+    ovs_be32 peer;          /* Features advertised by peer. */
+
+    ovs_be32 curr_speed;    /* Current port bitrate in kbps. */
+    ovs_be32 max_speed;     /* Max port bitrate in kbps */
+};
+
+/* Modify behavior of the physical port */
+struct ofp11_port_mod {
+    struct ofp_header header;
+    ovs_be32 port_no;
+    uint8_t pad[4];
+    uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
+                                      configurable.  This is used to
+                                      sanity-check the request, so it must
+                                      be the same as returned in an
+                                      ofp11_port struct. */
+    uint8_t pad2[2];        /* Pad to 64 bits. */
+    ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
+    ovs_be32 mask;          /* Bitmap of OFPPC_* flags to be changed. */
+
+    ovs_be32 advertise;     /* Bitmap of OFPPF_* and OFPPF11_*.  Zero all bits
+                               to prevent any action taking place. */
+    uint8_t pad3[4];        /* Pad to 64 bits. */
+};
+OFP_ASSERT(sizeof(struct ofp11_port_mod) == 40);
+
+/* OpenFlow 1.1 specific capabilities supported by the datapath (struct
+ * ofp_switch_features, member capabilities). */
+enum ofp11_capabilities {
+    OFPC11_GROUP_STATS    = 1 << 3,  /* Group statistics. */
+};
+
 enum ofp11_action_type {
     OFPAT11_OUTPUT,           /* Output to switch port. */
     OFPAT11_SET_VLAN_VID,     /* Set the 802.1q VLAN id. */
index d0f4b18..89c191b 100644 (file)
@@ -104,4 +104,94 @@ enum ofp_type {
     OFPT_PORT_STATUS,         /* Async message */
 };
 
+/* Header on all OpenFlow packets. */
+struct ofp_header {
+    uint8_t version;    /* An OpenFlow version number, e.g. OFP10_VERSION. */
+    uint8_t type;       /* One of the OFPT_ constants. */
+    ovs_be16 length;    /* Length including this ofp_header. */
+    ovs_be32 xid;       /* Transaction id associated with this packet.
+                           Replies use the same id as was in the request
+                           to facilitate pairing. */
+};
+OFP_ASSERT(sizeof(struct ofp_header) == 8);
+
+/* Common flags to indicate behavior of the physical port.  These flags are
+ * used in ofp_port to describe the current configuration.  They are used in
+ * the ofp_port_mod message to configure the port's behavior.
+ */
+enum ofp_port_config {
+    OFPPC_PORT_DOWN    = 1 << 0,  /* Port is administratively down. */
+
+    OFPPC_NO_RECV      = 1 << 2,  /* Drop all packets received by port. */
+    OFPPC_NO_FWD       = 1 << 5,  /* Drop packets forwarded to port. */
+    OFPPC_NO_PACKET_IN = 1 << 6   /* Do not send packet-in msgs for port. */
+};
+
+/* Common current state of the physical port.  These are not configurable from
+ * the controller.
+ */
+enum ofp_port_state {
+    OFPPS_LINK_DOWN    = 1 << 0,  /* No physical link present. */
+};
+
+/* Common features of physical ports available in a datapath. */
+enum ofp_port_features {
+    OFPPF_10MB_HD    = 1 << 0,  /* 10 Mb half-duplex rate support. */
+    OFPPF_10MB_FD    = 1 << 1,  /* 10 Mb full-duplex rate support. */
+    OFPPF_100MB_HD   = 1 << 2,  /* 100 Mb half-duplex rate support. */
+    OFPPF_100MB_FD   = 1 << 3,  /* 100 Mb full-duplex rate support. */
+    OFPPF_1GB_HD     = 1 << 4,  /* 1 Gb half-duplex rate support. */
+    OFPPF_1GB_FD     = 1 << 5,  /* 1 Gb full-duplex rate support. */
+    OFPPF_10GB_FD    = 1 << 6,  /* 10 Gb full-duplex rate support. */
+};
+
+/* Switch features. */
+struct ofp_switch_features {
+    struct ofp_header header;
+    ovs_be64 datapath_id;   /* Datapath unique ID.  The lower 48-bits are for
+                               a MAC address, while the upper 16-bits are
+                               implementer-defined. */
+
+    ovs_be32 n_buffers;     /* Max packets buffered at once. */
+
+    uint8_t n_tables;       /* Number of tables supported by datapath. */
+    uint8_t pad[3];         /* Align to 64-bits. */
+
+    /* Features. */
+    ovs_be32 capabilities;  /* OFPC_*, OFPC10_*, OFPC11_*. */
+    ovs_be32 actions;       /* Bitmap of supported "ofp_action_type"s. */
+
+    /* Followed by an array of struct ofp10_phy_port or struct ofp11_port
+     * structures.  The number is inferred from header.length. */
+};
+OFP_ASSERT(sizeof(struct ofp_switch_features) == 32);
+
+/* Common capabilities supported by the datapath (struct ofp_switch_features,
+ * member capabilities). */
+enum ofp_capabilities {
+    OFPC_FLOW_STATS     = 1 << 0,  /* Flow statistics. */
+    OFPC_TABLE_STATS    = 1 << 1,  /* Table statistics. */
+    OFPC_PORT_STATS     = 1 << 2,  /* Port statistics. */
+    OFPC_IP_REASM       = 1 << 5,  /* Can reassemble IP fragments. */
+    OFPC_QUEUE_STATS    = 1 << 6,  /* Queue statistics. */
+    OFPC_ARP_MATCH_IP   = 1 << 7   /* Match IP addresses in ARP
+                                      pkts. */
+};
+
+/* What changed about the physical port */
+enum ofp_port_reason {
+    OFPPR_ADD,              /* The port was added. */
+    OFPPR_DELETE,           /* The port was removed. */
+    OFPPR_MODIFY            /* Some attribute of the port has changed. */
+};
+
+/* A physical port has changed in the datapath */
+struct ofp_port_status {
+    struct ofp_header header;
+    uint8_t reason;          /* One of OFPPR_*. */
+    uint8_t pad[7];          /* Align to 64-bits. */
+    /* Followed by struct ofp10_phy_port or struct ofp11_port.  */
+};
+OFP_ASSERT(sizeof(struct ofp_port_status) == 16);
+
 #endif /* openflow/openflow-common.h */
index fb529f5..9e36db8 100644 (file)
@@ -77,8 +77,8 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
 static void queue_tx(struct lswitch *, struct rconn *, struct ofpbuf *);
 static void send_features_request(struct lswitch *, struct rconn *);
 
-static void process_switch_features(struct lswitch *,
-                                    struct ofp_switch_features *);
+static enum ofperr process_switch_features(struct lswitch *,
+                                           struct ofp_switch_features *);
 static void process_packet_in(struct lswitch *, struct rconn *,
                               const struct ofp_packet_in *);
 static void process_echo_request(struct lswitch *, struct rconn *,
@@ -347,27 +347,32 @@ queue_tx(struct lswitch *sw, struct rconn *rconn, struct ofpbuf *b)
     }
 }
 
-static void
+static enum ofperr
 process_switch_features(struct lswitch *sw, struct ofp_switch_features *osf)
 {
-    size_t n_ports;
-    size_t i;
-
-    sw->datapath_id = ntohll(osf->datapath_id);
+    struct ofputil_switch_features features;
+    struct ofputil_phy_port port;
+    enum ofperr error;
+    struct ofpbuf b;
+
+    error = ofputil_decode_switch_features(osf, &features, &b);
+    if (error) {
+        VLOG_ERR("received invalid switch feature reply (%s)",
+                 ofperr_to_string(error));
+        return error;
+    }
 
-    n_ports = (ntohs(osf->header.length) - sizeof *osf) / sizeof *osf->ports;
-    for (i = 0; i < n_ports; i++) {
-        struct ofp_phy_port *opp = &osf->ports[i];
-        struct lswitch_port *lp;
+    sw->datapath_id = features.datapath_id;
 
-        opp->name[OFP_MAX_PORT_NAME_LEN - 1] = '\0';
-        lp = shash_find_data(&sw->queue_names, opp->name);
+    while (!ofputil_pull_switch_features_port(&b, &port)) {
+        struct lswitch_port *lp = shash_find_data(&sw->queue_names, port.name);
         if (lp && hmap_node_is_null(&lp->hmap_node)) {
-            lp->port_no = ntohs(opp->port_no);
+            lp->port_no = port.port_no;
             hmap_insert(&sw->queue_numbers, &lp->hmap_node,
                         hash_int(lp->port_no, 0));
         }
     }
+    return 0;
 }
 
 static uint16_t
index 28fa112..cef32f2 100644 (file)
@@ -126,6 +126,9 @@ enum ofperr {
     /* NX(1,515).  Must-be-zero field had nonzero value. */
     OFPERR_NXBRC_MUST_BE_ZERO,
 
+    /* NX(1,516).  The reason in an ofp_port_status message is not valid. */
+    OFPERR_NXBRC_BAD_REASON,
+
 /* ## ---------------- ## */
 /* ## OFPET_BAD_ACTION ## */
 /* ## ---------------- ## */
index 1d71fc9..79e23a9 100644 (file)
@@ -34,6 +34,7 @@
 #include "learn.h"
 #include "multipath.h"
 #include "meta-flow.h"
+#include "netdev.h"
 #include "nx-match.h"
 #include "ofp-errors.h"
 #include "ofp-util.h"
@@ -443,37 +444,38 @@ ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
 static int
 compare_ports(const void *a_, const void *b_)
 {
-    const struct ofp_phy_port *a = a_;
-    const struct ofp_phy_port *b = b_;
-    uint16_t ap = ntohs(a->port_no);
-    uint16_t bp = ntohs(b->port_no);
+    const struct ofputil_phy_port *a = a_;
+    const struct ofputil_phy_port *b = b_;
+    uint16_t ap = a->port_no;
+    uint16_t bp = b->port_no;
 
     return ap < bp ? -1 : ap > bp;
 }
 
-struct bit_name {
-    uint32_t bit;
-    const char *name;
-};
-
 static void
 ofp_print_bit_names(struct ds *string, uint32_t bits,
-                    const struct bit_name bit_names[])
+                    const char *(*bit_to_name)(uint32_t bit))
 {
     int n = 0;
+    int i;
 
     if (!bits) {
         ds_put_cstr(string, "0");
         return;
     }
 
-    for (; bits && bit_names->name; bit_names++) {
-        if (bits & bit_names->bit) {
-            if (n++) {
-                ds_put_char(string, ' ');
+    for (i = 0; i < 32; i++) {
+        uint32_t bit = UINT32_C(1) << i;
+
+        if (bits & bit) {
+            const char *name = bit_to_name(bit);
+            if (name) {
+                if (n++) {
+                    ds_put_char(string, ' ');
+                }
+                ds_put_cstr(string, name);
+                bits &= ~bit;
             }
-            ds_put_cstr(string, bit_names->name);
-            bits &= ~bit_names->bit;
         }
     }
 
@@ -485,55 +487,90 @@ ofp_print_bit_names(struct ds *string, uint32_t bits,
     }
 }
 
+static const char *
+netdev_feature_to_name(uint32_t bit)
+{
+    enum netdev_features f = bit;
+
+    switch (f) {
+    case NETDEV_F_10MB_HD:    return "10MB-HD";
+    case NETDEV_F_10MB_FD:    return "10MB-FD";
+    case NETDEV_F_100MB_HD:   return "100MB-HD";
+    case NETDEV_F_100MB_FD:   return "100MB-FD";
+    case NETDEV_F_1GB_HD:     return "1GB-HD";
+    case NETDEV_F_1GB_FD:     return "1GB-FD";
+    case NETDEV_F_10GB_FD:    return "10GB-FD";
+    case NETDEV_F_40GB_FD:    return "40GB-FD";
+    case NETDEV_F_100GB_FD:   return "100GB-FD";
+    case NETDEV_F_1TB_FD:     return "1TB-FD";
+    case NETDEV_F_OTHER:      return "OTHER";
+    case NETDEV_F_COPPER:     return "COPPER";
+    case NETDEV_F_FIBER:      return "FIBER";
+    case NETDEV_F_AUTONEG:    return "AUTO_NEG";
+    case NETDEV_F_PAUSE:      return "AUTO_PAUSE";
+    case NETDEV_F_PAUSE_ASYM: return "AUTO_PAUSE_ASYM";
+    }
+
+    return NULL;
+}
+
 static void
-ofp_print_port_features(struct ds *string, uint32_t features)
+ofp_print_port_features(struct ds *string, enum netdev_features features)
 {
-    static const struct bit_name feature_bits[] = {
-        { OFPPF_10MB_HD,    "10MB-HD" },
-        { OFPPF_10MB_FD,    "10MB-FD" },
-        { OFPPF_100MB_HD,   "100MB-HD" },
-        { OFPPF_100MB_FD,   "100MB-FD" },
-        { OFPPF_1GB_HD,     "1GB-HD" },
-        { OFPPF_1GB_FD,     "1GB-FD" },
-        { OFPPF_10GB_FD,    "10GB-FD" },
-        { OFPPF_COPPER,     "COPPER" },
-        { OFPPF_FIBER,      "FIBER" },
-        { OFPPF_AUTONEG,    "AUTO_NEG" },
-        { OFPPF_PAUSE,      "AUTO_PAUSE" },
-        { OFPPF_PAUSE_ASYM, "AUTO_PAUSE_ASYM" },
-        { 0,                NULL },
-    };
-
-    ofp_print_bit_names(string, features, feature_bits);
+    ofp_print_bit_names(string, features, netdev_feature_to_name);
     ds_put_char(string, '\n');
 }
 
+static const char *
+ofputil_port_config_to_name(uint32_t bit)
+{
+    enum ofputil_port_config pc = bit;
+
+    switch (pc) {
+    case OFPUTIL_PC_PORT_DOWN:    return "PORT_DOWN";
+    case OFPUTIL_PC_NO_STP:       return "NO_STP";
+    case OFPUTIL_PC_NO_RECV:      return "NO_RECV";
+    case OFPUTIL_PC_NO_RECV_STP:  return "NO_RECV_STP";
+    case OFPUTIL_PC_NO_FLOOD:     return "NO_FLOOD";
+    case OFPUTIL_PC_NO_FWD:       return "NO_FWD";
+    case OFPUTIL_PC_NO_PACKET_IN: return "NO_PACKET_IN";
+    }
+
+    return NULL;
+}
+
 static void
-ofp_print_port_config(struct ds *string, uint32_t config)
+ofp_print_port_config(struct ds *string, enum ofputil_port_config config)
 {
-    static const struct bit_name config_bits[] = {
-        { OFPPC_PORT_DOWN,    "PORT_DOWN" },
-        { OFPPC_NO_STP,       "NO_STP" },
-        { OFPPC_NO_RECV,      "NO_RECV" },
-        { OFPPC_NO_RECV_STP,  "NO_RECV_STP" },
-        { OFPPC_NO_FLOOD,     "NO_FLOOD" },
-        { OFPPC_NO_FWD,       "NO_FWD" },
-        { OFPPC_NO_PACKET_IN, "NO_PACKET_IN" },
-        { 0,                  NULL },
-    };
-
-    ofp_print_bit_names(string, config, config_bits);
+    ofp_print_bit_names(string, config, ofputil_port_config_to_name);
     ds_put_char(string, '\n');
 }
 
+static const char *
+ofputil_port_state_to_name(uint32_t bit)
+{
+    enum ofputil_port_state ps = bit;
+
+    switch (ps) {
+    case OFPUTIL_PS_LINK_DOWN: return "LINK_DOWN";
+    case OFPUTIL_PS_BLOCKED:   return "BLOCKED";
+    case OFPUTIL_PS_LIVE:      return "LIVE";
+
+    case OFPUTIL_PS_STP_LISTEN:
+    case OFPUTIL_PS_STP_LEARN:
+    case OFPUTIL_PS_STP_FORWARD:
+    case OFPUTIL_PS_STP_BLOCK:
+        /* Handled elsewhere. */
+        return NULL;
+    }
+
+    return NULL;
+}
+
 static void
-ofp_print_port_state(struct ds *string, uint32_t state)
+ofp_print_port_state(struct ds *string, enum ofputil_port_state state)
 {
-    static const struct bit_name state_bits[] = {
-        { OFPPS_LINK_DOWN, "LINK_DOWN" },
-        { 0,               NULL },
-    };
-    uint32_t stp_state;
+    enum ofputil_port_state stp_state;
 
     /* The STP state is a 2-bit field so it doesn't fit in with the bitmask
      * pattern.  We have to special case it.
@@ -542,25 +579,26 @@ ofp_print_port_state(struct ds *string, uint32_t state)
      * talking to OVS, so we'd always print STP_LISTEN in that case.
      * Therefore, we don't print anything at all if the value is STP_LISTEN, to
      * avoid confusing users. */
-    stp_state = state & OFPPS_STP_MASK;
+    stp_state = state & OFPUTIL_PS_STP_MASK;
     if (stp_state) {
-        ds_put_cstr(string, (stp_state == OFPPS_STP_LEARN ? "STP_LEARN"
-                             : stp_state == OFPPS_STP_FORWARD ? "STP_FORWARD"
-                             : "STP_BLOCK"));
-        state &= ~OFPPS_STP_MASK;
+        ds_put_cstr(string,
+                    (stp_state == OFPUTIL_PS_STP_LEARN ? "STP_LEARN"
+                     : stp_state == OFPUTIL_PS_STP_FORWARD ? "STP_FORWARD"
+                     : "STP_BLOCK"));
+        state &= ~OFPUTIL_PS_STP_MASK;
         if (state) {
-            ofp_print_bit_names(string, state, state_bits);
+            ofp_print_bit_names(string, state, ofputil_port_state_to_name);
         }
     } else {
-        ofp_print_bit_names(string, state, state_bits);
+        ofp_print_bit_names(string, state, ofputil_port_state_to_name);
     }
     ds_put_char(string, '\n');
 }
 
 static void
-ofp_print_phy_port(struct ds *string, const struct ofp_phy_port *port)
+ofp_print_phy_port(struct ds *string, const struct ofputil_phy_port *port)
 {
-    char name[OFP_MAX_PORT_NAME_LEN];
+    char name[sizeof port->name];
     int j;
 
     memcpy(name, port->name, sizeof name);
@@ -572,58 +610,141 @@ ofp_print_phy_port(struct ds *string, const struct ofp_phy_port *port)
     name[j] = '\0';
 
     ds_put_char(string, ' ');
-    ofputil_format_port(ntohs(port->port_no), string);
+    ofputil_format_port(port->port_no, string);
     ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT"\n",
                   name, ETH_ADDR_ARGS(port->hw_addr));
 
     ds_put_cstr(string, "     config:     ");
-    ofp_print_port_config(string, ntohl(port->config));
+    ofp_print_port_config(string, port->config);
 
     ds_put_cstr(string, "     state:      ");
-    ofp_print_port_state(string, ntohl(port->state));
+    ofp_print_port_state(string, port->state);
 
     if (port->curr) {
         ds_put_format(string, "     current:    ");
-        ofp_print_port_features(string, ntohl(port->curr));
+        ofp_print_port_features(string, port->curr);
     }
     if (port->advertised) {
         ds_put_format(string, "     advertised: ");
-        ofp_print_port_features(string, ntohl(port->advertised));
+        ofp_print_port_features(string, port->advertised);
     }
     if (port->supported) {
         ds_put_format(string, "     supported:  ");
-        ofp_print_port_features(string, ntohl(port->supported));
+        ofp_print_port_features(string, port->supported);
     }
     if (port->peer) {
         ds_put_format(string, "     peer:       ");
-        ofp_print_port_features(string, ntohl(port->peer));
+        ofp_print_port_features(string, port->peer);
     }
+    ds_put_format(string, "     speed: %"PRIu32" Mbps now, "
+                  "%"PRIu32" Mbps max\n",
+                  port->curr_speed / UINT32_C(1000),
+                  port->max_speed / UINT32_C(1000));
+}
+
+static const char *
+ofputil_capabilities_to_name(uint32_t bit)
+{
+    enum ofputil_capabilities capabilities = bit;
+
+    switch (capabilities) {
+    case OFPUTIL_C_FLOW_STATS:   return "FLOW_STATS";
+    case OFPUTIL_C_TABLE_STATS:  return "TABLE_STATS";
+    case OFPUTIL_C_PORT_STATS:   return "PORT_STATS";
+    case OFPUTIL_C_IP_REASM:     return "IP_REASM";
+    case OFPUTIL_C_QUEUE_STATS:  return "QUEUE_STATS";
+    case OFPUTIL_C_ARP_MATCH_IP: return "ARP_MATCH_IP";
+    case OFPUTIL_C_STP:          return "STP";
+    case OFPUTIL_C_GROUP_STATS:  return "GROUP_STATS";
+    }
+
+    return NULL;
+}
+
+static const char *
+ofputil_action_bitmap_to_name(uint32_t bit)
+{
+    enum ofputil_action_bitmap action = bit;
+
+    switch (action) {
+    case OFPUTIL_A_OUTPUT:         return "OUTPUT";
+    case OFPUTIL_A_SET_VLAN_VID:   return "SET_VLAN_VID";
+    case OFPUTIL_A_SET_VLAN_PCP:   return "SET_VLAN_PCP";
+    case OFPUTIL_A_STRIP_VLAN:     return "STRIP_VLAN";
+    case OFPUTIL_A_SET_DL_SRC:     return "SET_DL_SRC";
+    case OFPUTIL_A_SET_DL_DST:     return "SET_DL_DST";
+    case OFPUTIL_A_SET_NW_SRC:     return "SET_NW_SRC";
+    case OFPUTIL_A_SET_NW_DST:     return "SET_NW_DST";
+    case OFPUTIL_A_SET_NW_ECN:     return "SET_NW_ECN";
+    case OFPUTIL_A_SET_NW_TOS:     return "SET_NW_TOS";
+    case OFPUTIL_A_SET_TP_SRC:     return "SET_TP_SRC";
+    case OFPUTIL_A_SET_TP_DST:     return "SET_TP_DST";
+    case OFPUTIL_A_ENQUEUE:        return "ENQUEUE";
+    case OFPUTIL_A_COPY_TTL_OUT:   return "COPY_TTL_OUT";
+    case OFPUTIL_A_COPY_TTL_IN:    return "COPY_TTL_IN";
+    case OFPUTIL_A_SET_MPLS_LABEL: return "SET_MPLS_LABEL";
+    case OFPUTIL_A_SET_MPLS_TC:    return "SET_MPLS_TC";
+    case OFPUTIL_A_SET_MPLS_TTL:   return "SET_MPLS_TTL";
+    case OFPUTIL_A_DEC_MPLS_TTL:   return "DEC_MPLS_TTL";
+    case OFPUTIL_A_PUSH_VLAN:      return "PUSH_VLAN";
+    case OFPUTIL_A_POP_VLAN:       return "POP_VLAN";
+    case OFPUTIL_A_PUSH_MPLS:      return "PUSH_MPLS";
+    case OFPUTIL_A_POP_MPLS:       return "POP_MPLS";
+    case OFPUTIL_A_SET_QUEUE:      return "SET_QUEUE";
+    case OFPUTIL_A_GROUP:          return "GROUP";
+    case OFPUTIL_A_SET_NW_TTL:     return "SET_NW_TTL";
+    case OFPUTIL_A_DEC_NW_TTL:     return "DEC_NW_TTL";
+    }
+
+    return NULL;
 }
 
 static void
 ofp_print_switch_features(struct ds *string,
                           const struct ofp_switch_features *osf)
 {
-    size_t len = ntohs(osf->header.length);
-    struct ofp_phy_port *port_list;
-    int n_ports;
-    int i;
+    struct ofputil_switch_features features;
+    struct ofputil_phy_port *ports;
+    enum ofperr error;
+    struct ofpbuf b;
+    size_t n_ports;
+    size_t i;
 
-    ds_put_format(string, " ver:0x%x, dpid:%016"PRIx64"\n",
-            osf->header.version, ntohll(osf->datapath_id));
-    ds_put_format(string, "n_tables:%d, n_buffers:%d\n", osf->n_tables,
-            ntohl(osf->n_buffers));
-    ds_put_format(string, "features: capabilities:%#x, actions:%#x\n",
-           ntohl(osf->capabilities), ntohl(osf->actions));
+    error = ofputil_decode_switch_features(osf, &features, &b);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
 
-    n_ports = (len - sizeof *osf) / sizeof *osf->ports;
+    ds_put_format(string, " dpid:%016"PRIx64"\n", features.datapath_id);
+    ds_put_format(string, "n_tables:%"PRIu8", n_buffers:%"PRIu32"\n",
+                  features.n_tables, features.n_buffers);
 
-    port_list = xmemdup(osf->ports, len - sizeof *osf);
-    qsort(port_list, n_ports, sizeof *port_list, compare_ports);
+    ds_put_cstr(string, "capabilities: ");
+    ofp_print_bit_names(string, features.capabilities,
+                        ofputil_capabilities_to_name);
+    ds_put_char(string, '\n');
+
+    ds_put_cstr(string, "actions: ");
+    ofp_print_bit_names(string, features.actions,
+                        ofputil_action_bitmap_to_name);
+    ds_put_char(string, '\n');
+
+    n_ports = ofputil_count_phy_ports(osf);
+
+    ports = xmalloc(n_ports * sizeof *ports);
     for (i = 0; i < n_ports; i++) {
-        ofp_print_phy_port(string, &port_list[i]);
+        error = ofputil_pull_switch_features_port(&b, &ports[i]);
+        if (error) {
+            ofp_print_error(string, error);
+            return;
+        }
+    }
+    qsort(ports, n_ports, sizeof *ports, compare_ports);
+    for (i = 0; i < n_ports; i++) {
+        ofp_print_phy_port(string, &ports[i]);
     }
-    free(port_list);
+    free(ports);
 }
 
 static void
@@ -938,14 +1059,29 @@ ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
 }
 
 static void
-ofp_print_port_mod(struct ds *string, const struct ofp_port_mod *opm)
+ofp_print_port_mod(struct ds *string, const struct ofp_header *oh)
 {
-    ds_put_format(string, "port: %d: addr:"ETH_ADDR_FMT", config: %#x, mask:%#x\n",
-            ntohs(opm->port_no), ETH_ADDR_ARGS(opm->hw_addr),
-            ntohl(opm->config), ntohl(opm->mask));
+    struct ofputil_port_mod pm;
+    enum ofperr error;
+
+    error = ofputil_decode_port_mod(oh, &pm);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    ds_put_format(string, "port: %"PRIu16": addr:"ETH_ADDR_FMT"\n",
+                  pm.port_no, ETH_ADDR_ARGS(pm.hw_addr));
+
+    ds_put_format(string, "     config: ");
+    ofp_print_port_config(string, pm.config);
+
+    ds_put_format(string, "     mask:   ");
+    ofp_print_port_config(string, pm.mask);
+
     ds_put_format(string, "     advertise: ");
-    if (opm->advertise) {
-        ofp_print_port_features(string, ntohl(opm->advertise));
+    if (pm.advertise) {
+        ofp_print_port_features(string, pm.advertise);
     } else {
         ds_put_format(string, "UNCHANGED\n");
     }
@@ -992,15 +1128,24 @@ ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
 static void
 ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops)
 {
-    if (ops->reason == OFPPR_ADD) {
+    struct ofputil_port_status ps;
+    enum ofperr error;
+
+    error = ofputil_decode_port_status(ops, &ps);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    if (ps.reason == OFPPR_ADD) {
         ds_put_format(string, " ADD:");
-    } else if (ops->reason == OFPPR_DELETE) {
+    } else if (ps.reason == OFPPR_DELETE) {
         ds_put_format(string, " DEL:");
-    } else if (ops->reason == OFPPR_MODIFY) {
+    } else if (ps.reason == OFPPR_MODIFY) {
         ds_put_format(string, " MOD:");
     }
 
-    ofp_print_phy_port(string, &ops->desc);
+    ofp_print_phy_port(string, &ps.desc);
 }
 
 static void
index e29450f..3099b0b 100644 (file)
@@ -28,8 +28,8 @@
 #include "classifier.h"
 #include "dynamic-string.h"
 #include "learn.h"
-#include "multipath.h"
 #include "meta-flow.h"
+#include "multipath.h"
 #include "netdev.h"
 #include "nx-match.h"
 #include "ofp-errors.h"
@@ -698,7 +698,10 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
 
         { OFPUTIL_OFPT_FEATURES_REPLY, OFP10_VERSION,
           OFPT_FEATURES_REPLY, "OFPT_FEATURES_REPLY",
-          sizeof(struct ofp_switch_features), sizeof(struct ofp_phy_port) },
+          sizeof(struct ofp_switch_features), sizeof(struct ofp10_phy_port) },
+        { OFPUTIL_OFPT_FEATURES_REPLY, OFP11_VERSION,
+          OFPT_FEATURES_REPLY, "OFPT_FEATURES_REPLY",
+          sizeof(struct ofp_switch_features), sizeof(struct ofp11_port) },
 
         { OFPUTIL_OFPT_GET_CONFIG_REQUEST, OFP10_VERSION,
           OFPT_GET_CONFIG_REQUEST, "OFPT_GET_CONFIG_REQUEST",
@@ -722,7 +725,10 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
 
         { OFPUTIL_OFPT_PORT_STATUS, OFP10_VERSION,
           OFPT_PORT_STATUS, "OFPT_PORT_STATUS",
-          sizeof(struct ofp_port_status), 0 },
+          sizeof(struct ofp_port_status) + sizeof(struct ofp10_phy_port), 0 },
+        { OFPUTIL_OFPT_PORT_STATUS, OFP11_VERSION,
+          OFPT_PORT_STATUS, "OFPT_PORT_STATUS",
+          sizeof(struct ofp_port_status) + sizeof(struct ofp11_port), 0 },
 
         { OFPUTIL_OFPT_PACKET_OUT, OFP10_VERSION,
           OFPT10_PACKET_OUT, "OFPT_PACKET_OUT",
@@ -734,7 +740,10 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
 
         { OFPUTIL_OFPT_PORT_MOD, OFP10_VERSION,
           OFPT10_PORT_MOD, "OFPT_PORT_MOD",
-          sizeof(struct ofp_port_mod), 0 },
+          sizeof(struct ofp10_port_mod), 0 },
+        { OFPUTIL_OFPT_PORT_MOD, OFP11_VERSION,
+          OFPT11_PORT_MOD, "OFPT_PORT_MOD",
+          sizeof(struct ofp11_port_mod), 0 },
 
         { 0, OFP10_VERSION,
           OFPT10_STATS_REQUEST, "OFPT_STATS_REQUEST",
@@ -878,6 +887,22 @@ ofputil_protocol_from_ofp_version(int version)
     }
 }
 
+/* Returns the OpenFlow protocol version number (e.g. OFP10_VERSION or
+ * OFP11_VERSION) that corresponds to 'protocol'. */
+uint8_t
+ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol)
+{
+    switch (protocol) {
+    case OFPUTIL_P_OF10:
+    case OFPUTIL_P_OF10_TID:
+    case OFPUTIL_P_NXM:
+    case OFPUTIL_P_NXM_TID:
+        return OFP10_VERSION;
+    }
+
+    NOT_REACHED();
+}
+
 /* Returns true if 'protocol' is a single OFPUTIL_P_* value, false
  * otherwise. */
 bool
@@ -2237,25 +2262,511 @@ BUILD_ASSERT_DECL((int) NETDEV_F_1GB_FD     == OFPPF_1GB_FD);   /* bit 5 */
 BUILD_ASSERT_DECL((int) NETDEV_F_10GB_FD    == OFPPF_10GB_FD);  /* bit 6 */
 
 /* NETDEV_F_ bits 11...15 are OFPPF10_ bits 7...11: */
-BUILD_ASSERT_DECL((int) NETDEV_F_COPPER == (OFPPF_COPPER << 4));
-BUILD_ASSERT_DECL((int) NETDEV_F_FIBER == (OFPPF_FIBER << 4));
-BUILD_ASSERT_DECL((int) NETDEV_F_AUTONEG == (OFPPF_AUTONEG << 4));
-BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE == (OFPPF_PAUSE << 4));
-BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE_ASYM == (OFPPF_PAUSE_ASYM << 4));
+BUILD_ASSERT_DECL((int) NETDEV_F_COPPER == (OFPPF10_COPPER << 4));
+BUILD_ASSERT_DECL((int) NETDEV_F_FIBER == (OFPPF10_FIBER << 4));
+BUILD_ASSERT_DECL((int) NETDEV_F_AUTONEG == (OFPPF10_AUTONEG << 4));
+BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE == (OFPPF10_PAUSE << 4));
+BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE_ASYM == (OFPPF10_PAUSE_ASYM << 4));
 
-enum netdev_features
-ofputil_netdev_port_features_from_ofp10(ovs_be32 ofp10_)
+static enum netdev_features
+netdev_port_features_from_ofp10(ovs_be32 ofp10_)
 {
     uint32_t ofp10 = ntohl(ofp10_);
     return (ofp10 & 0x7f) | ((ofp10 & 0xf80) << 4);
 }
 
-ovs_be32
-ofputil_netdev_port_features_to_ofp10(enum netdev_features features)
+static ovs_be32
+netdev_port_features_to_ofp10(enum netdev_features features)
 {
     return htonl((features & 0x7f) | ((features & 0xf800) >> 4));
 }
 
+BUILD_ASSERT_DECL((int) NETDEV_F_10MB_HD    == OFPPF_10MB_HD);     /* bit 0 */
+BUILD_ASSERT_DECL((int) NETDEV_F_10MB_FD    == OFPPF_10MB_FD);     /* bit 1 */
+BUILD_ASSERT_DECL((int) NETDEV_F_100MB_HD   == OFPPF_100MB_HD);    /* bit 2 */
+BUILD_ASSERT_DECL((int) NETDEV_F_100MB_FD   == OFPPF_100MB_FD);    /* bit 3 */
+BUILD_ASSERT_DECL((int) NETDEV_F_1GB_HD     == OFPPF_1GB_HD);      /* bit 4 */
+BUILD_ASSERT_DECL((int) NETDEV_F_1GB_FD     == OFPPF_1GB_FD);      /* bit 5 */
+BUILD_ASSERT_DECL((int) NETDEV_F_10GB_FD    == OFPPF_10GB_FD);     /* bit 6 */
+BUILD_ASSERT_DECL((int) NETDEV_F_40GB_FD    == OFPPF11_40GB_FD);   /* bit 7 */
+BUILD_ASSERT_DECL((int) NETDEV_F_100GB_FD   == OFPPF11_100GB_FD);  /* bit 8 */
+BUILD_ASSERT_DECL((int) NETDEV_F_1TB_FD     == OFPPF11_1TB_FD);    /* bit 9 */
+BUILD_ASSERT_DECL((int) NETDEV_F_OTHER      == OFPPF11_OTHER);     /* bit 10 */
+BUILD_ASSERT_DECL((int) NETDEV_F_COPPER     == OFPPF11_COPPER);    /* bit 11 */
+BUILD_ASSERT_DECL((int) NETDEV_F_FIBER      == OFPPF11_FIBER);     /* bit 12 */
+BUILD_ASSERT_DECL((int) NETDEV_F_AUTONEG    == OFPPF11_AUTONEG);   /* bit 13 */
+BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE      == OFPPF11_PAUSE);     /* bit 14 */
+BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE_ASYM == OFPPF11_PAUSE_ASYM);/* bit 15 */
+
+static enum netdev_features
+netdev_port_features_from_ofp11(ovs_be32 ofp11)
+{
+    return ntohl(ofp11) & 0xffff;
+}
+
+static ovs_be32
+netdev_port_features_to_ofp11(enum netdev_features features)
+{
+    return htonl(features & 0xffff);
+}
+
+static enum ofperr
+ofputil_decode_ofp10_phy_port(struct ofputil_phy_port *pp,
+                              const struct ofp10_phy_port *opp)
+{
+    memset(pp, 0, sizeof *pp);
+
+    pp->port_no = ntohs(opp->port_no);
+    memcpy(pp->hw_addr, opp->hw_addr, OFP_ETH_ALEN);
+    ovs_strlcpy(pp->name, opp->name, OFP_MAX_PORT_NAME_LEN);
+
+    pp->config = ntohl(opp->config) & OFPPC10_ALL;
+    pp->state = ntohl(opp->state) & OFPPS10_ALL;
+
+    pp->curr = netdev_port_features_from_ofp10(opp->curr);
+    pp->advertised = netdev_port_features_from_ofp10(opp->advertised);
+    pp->supported = netdev_port_features_from_ofp10(opp->supported);
+    pp->peer = netdev_port_features_from_ofp10(opp->peer);
+
+    pp->curr_speed = netdev_features_to_bps(pp->curr) / 1000;
+    pp->max_speed = netdev_features_to_bps(pp->supported) / 1000;
+
+    return 0;
+}
+
+static enum ofperr
+ofputil_decode_ofp11_port(struct ofputil_phy_port *pp,
+                          const struct ofp11_port *op)
+{
+    enum ofperr error;
+
+    memset(pp, 0, sizeof *pp);
+
+    error = ofputil_port_from_ofp11(op->port_no, &pp->port_no);
+    if (error) {
+        return error;
+    }
+    memcpy(pp->hw_addr, op->hw_addr, OFP_ETH_ALEN);
+    ovs_strlcpy(pp->name, op->name, OFP_MAX_PORT_NAME_LEN);
+
+    pp->config = ntohl(op->config) & OFPPC11_ALL;
+    pp->state = ntohl(op->state) & OFPPC11_ALL;
+
+    pp->curr = netdev_port_features_from_ofp11(op->curr);
+    pp->advertised = netdev_port_features_from_ofp11(op->advertised);
+    pp->supported = netdev_port_features_from_ofp11(op->supported);
+    pp->peer = netdev_port_features_from_ofp11(op->peer);
+
+    pp->curr_speed = ntohl(op->curr_speed);
+    pp->max_speed = ntohl(op->max_speed);
+
+    return 0;
+}
+
+static int
+ofputil_pull_phy_port(uint8_t ofp_version, struct ofpbuf *b,
+                      struct ofputil_phy_port *pp)
+{
+    if (ofp_version == OFP10_VERSION) {
+        const struct ofp10_phy_port *opp = ofpbuf_try_pull(b, sizeof *opp);
+        return opp ? ofputil_decode_ofp10_phy_port(pp, opp) : EOF;
+    } else {
+        const struct ofp11_port *op = ofpbuf_try_pull(b, sizeof *op);
+        return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
+    }
+}
+
+static void
+ofputil_encode_ofp10_phy_port(const struct ofputil_phy_port *pp,
+                              struct ofp10_phy_port *opp)
+{
+    memset(opp, 0, sizeof *opp);
+
+    opp->port_no = htons(pp->port_no);
+    memcpy(opp->hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+    ovs_strlcpy(opp->name, pp->name, OFP_MAX_PORT_NAME_LEN);
+
+    opp->config = htonl(pp->config & OFPPC10_ALL);
+    opp->state = htonl(pp->state & OFPPS10_ALL);
+
+    opp->curr = netdev_port_features_to_ofp10(pp->curr);
+    opp->advertised = netdev_port_features_to_ofp10(pp->advertised);
+    opp->supported = netdev_port_features_to_ofp10(pp->supported);
+    opp->peer = netdev_port_features_to_ofp10(pp->peer);
+}
+
+static void
+ofputil_encode_ofp11_port(const struct ofputil_phy_port *pp,
+                          struct ofp11_port *op)
+{
+    memset(op, 0, sizeof *op);
+
+    op->port_no = ofputil_port_to_ofp11(pp->port_no);
+    memcpy(op->hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+    ovs_strlcpy(op->name, pp->name, OFP_MAX_PORT_NAME_LEN);
+
+    op->config = htonl(pp->config & OFPPC11_ALL);
+    op->state = htonl(pp->state & OFPPS11_ALL);
+
+    op->curr = netdev_port_features_to_ofp11(pp->curr);
+    op->advertised = netdev_port_features_to_ofp11(pp->advertised);
+    op->supported = netdev_port_features_to_ofp11(pp->supported);
+    op->peer = netdev_port_features_to_ofp11(pp->peer);
+
+    op->curr_speed = htonl(pp->curr_speed);
+    op->max_speed = htonl(pp->max_speed);
+}
+
+static void
+ofputil_put_phy_port(uint8_t ofp_version, const struct ofputil_phy_port *pp,
+                     struct ofpbuf *b)
+{
+    if (ofp_version == OFP10_VERSION) {
+        struct ofp10_phy_port *opp;
+        if (b->size + sizeof *opp <= UINT16_MAX) {
+            opp = ofpbuf_put_uninit(b, sizeof *opp);
+            ofputil_encode_ofp10_phy_port(pp, opp);
+        }
+    } else {
+        struct ofp11_port *op;
+        if (b->size + sizeof *op <= UINT16_MAX) {
+            op = ofpbuf_put_uninit(b, sizeof *op);
+            ofputil_encode_ofp11_port(pp, op);
+        }
+    }
+}
+\f
+/* ofputil_switch_features */
+
+#define OFPC_COMMON (OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | \
+                     OFPC_IP_REASM | OFPC_QUEUE_STATS | OFPC_ARP_MATCH_IP)
+BUILD_ASSERT_DECL((int) OFPUTIL_C_FLOW_STATS == OFPC_FLOW_STATS);
+BUILD_ASSERT_DECL((int) OFPUTIL_C_TABLE_STATS == OFPC_TABLE_STATS);
+BUILD_ASSERT_DECL((int) OFPUTIL_C_PORT_STATS == OFPC_PORT_STATS);
+BUILD_ASSERT_DECL((int) OFPUTIL_C_IP_REASM == OFPC_IP_REASM);
+BUILD_ASSERT_DECL((int) OFPUTIL_C_QUEUE_STATS == OFPC_QUEUE_STATS);
+BUILD_ASSERT_DECL((int) OFPUTIL_C_ARP_MATCH_IP == OFPC_ARP_MATCH_IP);
+
+struct ofputil_action_bit_translation {
+    enum ofputil_action_bitmap ofputil_bit;
+    int of_bit;
+};
+
+static const struct ofputil_action_bit_translation of10_action_bits[] = {
+    { OFPUTIL_A_OUTPUT,       OFPAT10_OUTPUT },
+    { OFPUTIL_A_SET_VLAN_VID, OFPAT10_SET_VLAN_VID },
+    { OFPUTIL_A_SET_VLAN_PCP, OFPAT10_SET_VLAN_PCP },
+    { OFPUTIL_A_STRIP_VLAN,   OFPAT10_STRIP_VLAN },
+    { OFPUTIL_A_SET_DL_SRC,   OFPAT10_SET_DL_SRC },
+    { OFPUTIL_A_SET_DL_DST,   OFPAT10_SET_DL_DST },
+    { OFPUTIL_A_SET_NW_SRC,   OFPAT10_SET_NW_SRC },
+    { OFPUTIL_A_SET_NW_DST,   OFPAT10_SET_NW_DST },
+    { OFPUTIL_A_SET_NW_TOS,   OFPAT10_SET_NW_TOS },
+    { OFPUTIL_A_SET_TP_SRC,   OFPAT10_SET_TP_SRC },
+    { OFPUTIL_A_SET_TP_DST,   OFPAT10_SET_TP_DST },
+    { OFPUTIL_A_ENQUEUE,      OFPAT10_ENQUEUE },
+    { 0, 0 },
+};
+
+static const struct ofputil_action_bit_translation of11_action_bits[] = {
+    { OFPUTIL_A_OUTPUT,         OFPAT11_OUTPUT },
+    { OFPUTIL_A_SET_VLAN_VID,   OFPAT11_SET_VLAN_VID },
+    { OFPUTIL_A_SET_VLAN_PCP,   OFPAT11_SET_VLAN_PCP },
+    { OFPUTIL_A_SET_DL_SRC,     OFPAT11_SET_DL_SRC },
+    { OFPUTIL_A_SET_DL_DST,     OFPAT11_SET_DL_DST },
+    { OFPUTIL_A_SET_NW_SRC,     OFPAT11_SET_NW_SRC },
+    { OFPUTIL_A_SET_NW_DST,     OFPAT11_SET_NW_DST },
+    { OFPUTIL_A_SET_NW_TOS,     OFPAT11_SET_NW_TOS },
+    { OFPUTIL_A_SET_NW_ECN,     OFPAT11_SET_NW_ECN },
+    { OFPUTIL_A_SET_TP_SRC,     OFPAT11_SET_TP_SRC },
+    { OFPUTIL_A_SET_TP_DST,     OFPAT11_SET_TP_DST },
+    { OFPUTIL_A_COPY_TTL_OUT,   OFPAT11_COPY_TTL_OUT },
+    { OFPUTIL_A_COPY_TTL_IN,    OFPAT11_COPY_TTL_IN },
+    { OFPUTIL_A_SET_MPLS_LABEL, OFPAT11_SET_MPLS_LABEL },
+    { OFPUTIL_A_SET_MPLS_TC,    OFPAT11_SET_MPLS_TC },
+    { OFPUTIL_A_SET_MPLS_TTL,   OFPAT11_SET_MPLS_TTL },
+    { OFPUTIL_A_DEC_MPLS_TTL,   OFPAT11_DEC_MPLS_TTL },
+    { OFPUTIL_A_PUSH_VLAN,      OFPAT11_PUSH_VLAN },
+    { OFPUTIL_A_POP_VLAN,       OFPAT11_POP_VLAN },
+    { OFPUTIL_A_PUSH_MPLS,      OFPAT11_PUSH_MPLS },
+    { OFPUTIL_A_POP_MPLS,       OFPAT11_POP_MPLS },
+    { OFPUTIL_A_SET_QUEUE,      OFPAT11_SET_QUEUE },
+    { OFPUTIL_A_GROUP,          OFPAT11_GROUP },
+    { OFPUTIL_A_SET_NW_TTL,     OFPAT11_SET_NW_TTL },
+    { OFPUTIL_A_DEC_NW_TTL,     OFPAT11_DEC_NW_TTL },
+    { 0, 0 },
+};
+
+static enum ofputil_action_bitmap
+decode_action_bits(ovs_be32 of_actions,
+                   const struct ofputil_action_bit_translation *x)
+{
+    enum ofputil_action_bitmap ofputil_actions;
+
+    ofputil_actions = 0;
+    for (; x->ofputil_bit; x++) {
+        if (of_actions & htonl(1u << x->of_bit)) {
+            ofputil_actions |= x->ofputil_bit;
+        }
+    }
+    return ofputil_actions;
+}
+
+/* Decodes an OpenFlow 1.0 or 1.1 "switch_features" structure 'osf' into an
+ * abstract representation in '*features'.  Initializes '*b' to iterate over
+ * the OpenFlow port structures following 'osf' with later calls to
+ * ofputil_pull_switch_features_port().  Returns 0 if successful, otherwise an
+ * OFPERR_* value.  */
+enum ofperr
+ofputil_decode_switch_features(const struct ofp_switch_features *osf,
+                               struct ofputil_switch_features *features,
+                               struct ofpbuf *b)
+{
+    ofpbuf_use_const(b, osf, ntohs(osf->header.length));
+    ofpbuf_pull(b, sizeof *osf);
+    b->l2 = (struct ofputil_switch_features *) osf;
+
+    features->datapath_id = ntohll(osf->datapath_id);
+    features->n_buffers = ntohl(osf->n_buffers);
+    features->n_tables = osf->n_tables;
+
+    features->capabilities = ntohl(osf->capabilities) & OFPC_COMMON;
+    if (osf->header.version == OFP10_VERSION) {
+        if (b->size % sizeof(struct ofp10_phy_port)) {
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+
+        if (osf->capabilities & htonl(OFPC10_STP)) {
+            features->capabilities |= OFPUTIL_C_STP;
+        }
+        features->actions = decode_action_bits(osf->actions, of10_action_bits);
+    } else if (osf->header.version == OFP11_VERSION) {
+        if (b->size % sizeof(struct ofp11_port)) {
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+
+        if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) {
+            features->capabilities |= OFPUTIL_C_GROUP_STATS;
+        }
+        features->actions = decode_action_bits(osf->actions, of11_action_bits);
+    } else {
+        return OFPERR_OFPBRC_BAD_VERSION;
+    }
+
+    return 0;
+}
+
+/* Given a buffer 'b' that was initialized by a previous successful call to
+ * ofputil_decode_switch_features(), tries to decode an OpenFlow port structure
+ * following the main switch features information.  If successful, initializes
+ * '*pp' with an abstract representation of the port and returns 0.  If no
+ * ports remained to be decoded, returns EOF.  On an error, returns a positive
+ * OFPERR_* value.  */
+int
+ofputil_pull_switch_features_port(struct ofpbuf *b,
+                                  struct ofputil_phy_port *pp)
+{
+    const struct ofp_switch_features *osf = b->l2;
+    return ofputil_pull_phy_port(osf->header.version, b, pp);
+}
+
+/* Returns the number of OpenFlow port structures that follow the main switch
+ * features information in '*osf'.  The return value is only guaranteed to be
+ * accurate if '*osf' is well-formed, that is, if
+ * ofputil_decode_switch_features() can process '*osf' successfully. */
+size_t
+ofputil_count_phy_ports(const struct ofp_switch_features *osf)
+{
+    size_t ports_len = ntohs(osf->header.length) - sizeof *osf;
+    return (osf->header.version == OFP10_VERSION
+            ? ports_len / sizeof(struct ofp10_phy_port)
+            : ports_len / sizeof(struct ofp11_port));
+}
+
+static ovs_be32
+encode_action_bits(enum ofputil_action_bitmap ofputil_actions,
+                   const struct ofputil_action_bit_translation *x)
+{
+    uint32_t of_actions;
+
+    of_actions = 0;
+    for (; x->ofputil_bit; x++) {
+        if (ofputil_actions & x->ofputil_bit) {
+            of_actions |= 1 << x->of_bit;
+        }
+    }
+    return htonl(of_actions);
+}
+
+/* Returns a buffer owned by the caller that encodes 'features' in the format
+ * required by 'protocol' with the given 'xid'.  The caller should append port
+ * information to the buffer with subsequent calls to
+ * ofputil_put_switch_features_port(). */
+struct ofpbuf *
+ofputil_encode_switch_features(const struct ofputil_switch_features *features,
+                               enum ofputil_protocol protocol, ovs_be32 xid)
+{
+    struct ofp_switch_features *osf;
+    struct ofpbuf *b;
+
+    osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, xid, &b);
+    osf->header.version = ofputil_protocol_to_ofp_version(protocol);
+    osf->datapath_id = htonll(features->datapath_id);
+    osf->n_buffers = htonl(features->n_buffers);
+    osf->n_tables = features->n_tables;
+
+    osf->capabilities = htonl(features->capabilities & OFPC_COMMON);
+    if (osf->header.version == OFP10_VERSION) {
+        if (features->capabilities & OFPUTIL_C_STP) {
+            osf->capabilities |= htonl(OFPC10_STP);
+        }
+        osf->actions = encode_action_bits(features->actions, of10_action_bits);
+    } else {
+        if (features->capabilities & OFPUTIL_C_GROUP_STATS) {
+            osf->capabilities |= htonl(OFPC11_GROUP_STATS);
+        }
+        osf->actions = encode_action_bits(features->actions, of11_action_bits);
+    }
+
+    return b;
+}
+
+/* Encodes 'pp' into the format required by the switch_features message already
+ * in 'b', which should have been returned by ofputil_encode_switch_features(),
+ * and appends the encoded version to 'b'. */
+void
+ofputil_put_switch_features_port(const struct ofputil_phy_port *pp,
+                                 struct ofpbuf *b)
+{
+    const struct ofp_switch_features *osf = b->data;
+
+    ofputil_put_phy_port(osf->header.version, pp, b);
+}
+\f
+/* ofputil_port_status */
+
+/* Decodes the OpenFlow "port status" message in '*ops' into an abstract form
+ * in '*ps'.  Returns 0 if successful, otherwise an OFPERR_* value. */
+enum ofperr
+ofputil_decode_port_status(const struct ofp_port_status *ops,
+                           struct ofputil_port_status *ps)
+{
+    struct ofpbuf b;
+    int retval;
+
+    if (ops->reason != OFPPR_ADD &&
+        ops->reason != OFPPR_DELETE &&
+        ops->reason != OFPPR_MODIFY) {
+        return OFPERR_NXBRC_BAD_REASON;
+    }
+    ps->reason = ops->reason;
+
+    ofpbuf_use_const(&b, ops, ntohs(ops->header.length));
+    ofpbuf_pull(&b, sizeof *ops);
+    retval = ofputil_pull_phy_port(ops->header.version, &b, &ps->desc);
+    assert(retval != EOF);
+    return retval;
+}
+
+/* Converts the abstract form of a "port status" message in '*ps' into an
+ * OpenFlow message suitable for 'protocol', and returns that encoded form in
+ * a buffer owned by the caller. */
+struct ofpbuf *
+ofputil_encode_port_status(const struct ofputil_port_status *ps,
+                           enum ofputil_protocol protocol)
+{
+    struct ofp_port_status *ops;
+    struct ofpbuf *b;
+
+    b = ofpbuf_new(sizeof *ops + sizeof(struct ofp11_port));
+    ops = put_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, htonl(0), b);
+    ops->header.version = ofputil_protocol_to_ofp_version(protocol);
+    ops->reason = ps->reason;
+    ofputil_put_phy_port(ops->header.version, &ps->desc, b);
+    update_openflow_length(b);
+    return b;
+}
+\f
+/* ofputil_port_mod */
+
+/* Decodes the OpenFlow "port mod" message in '*oh' into an abstract form in
+ * '*pm'.  Returns 0 if successful, otherwise an OFPERR_* value. */
+enum ofperr
+ofputil_decode_port_mod(const struct ofp_header *oh,
+                        struct ofputil_port_mod *pm)
+{
+    if (oh->version == OFP10_VERSION) {
+        const struct ofp10_port_mod *opm = (const struct ofp10_port_mod *) oh;
+
+        if (oh->length != htons(sizeof *opm)) {
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+
+        pm->port_no = ntohs(opm->port_no);
+        memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
+        pm->config = ntohl(opm->config) & OFPPC10_ALL;
+        pm->mask = ntohl(opm->mask) & OFPPC10_ALL;
+        pm->advertise = netdev_port_features_from_ofp10(opm->advertise);
+    } else if (oh->version == OFP11_VERSION) {
+        const struct ofp11_port_mod *opm = (const struct ofp11_port_mod *) oh;
+        enum ofperr error;
+
+        if (oh->length != htons(sizeof *opm)) {
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+
+        error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
+        if (error) {
+            return error;
+        }
+
+        memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
+        pm->config = ntohl(opm->config) & OFPPC11_ALL;
+        pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
+        pm->advertise = netdev_port_features_from_ofp11(opm->advertise);
+    } else {
+        return OFPERR_OFPBRC_BAD_VERSION;
+    }
+
+    pm->config &= pm->mask;
+    return 0;
+}
+
+/* Converts the abstract form of a "port mod" message in '*pm' into an OpenFlow
+ * message suitable for 'protocol', and returns that encoded form in a buffer
+ * owned by the caller. */
+struct ofpbuf *
+ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
+                        enum ofputil_protocol protocol)
+{
+    uint8_t ofp_version = ofputil_protocol_to_ofp_version(protocol);
+    struct ofpbuf *b;
+
+    if (ofp_version == OFP10_VERSION) {
+        struct ofp10_port_mod *opm;
+
+        opm = make_openflow(sizeof *opm, OFPT10_PORT_MOD, &b);
+        opm->port_no = htons(pm->port_no);
+        memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
+        opm->config = htonl(pm->config & OFPPC10_ALL);
+        opm->mask = htonl(pm->mask & OFPPC10_ALL);
+        opm->advertise = netdev_port_features_to_ofp10(pm->advertise);
+    } else if (ofp_version == OFP11_VERSION) {
+        struct ofp11_port_mod *opm;
+
+        opm = make_openflow(sizeof *opm, OFPT11_PORT_MOD, &b);
+        opm->port_no = htonl(pm->port_no);
+        memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
+        opm->config = htonl(pm->config & OFPPC11_ALL);
+        opm->mask = htonl(pm->mask & OFPPC11_ALL);
+        opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
+    } else {
+        NOT_REACHED();
+    }
+
+    return b;
+}
+
 struct ofpbuf *
 ofputil_encode_packet_out(const struct ofputil_packet_out *po)
 {
index 5004758..2172fd6 100644 (file)
@@ -151,6 +151,8 @@ extern enum ofputil_protocol ofputil_flow_dump_protocols[];
 extern size_t ofputil_n_flow_dump_protocols;
 
 enum ofputil_protocol ofputil_protocol_from_ofp_version(int version);
+uint8_t ofputil_protocol_to_ofp_version(enum ofputil_protocol);
+
 bool ofputil_protocol_is_valid(enum ofputil_protocol);
 enum ofputil_protocol ofputil_protocol_set_tid(enum ofputil_protocol,
                                                bool enable);
@@ -326,9 +328,144 @@ enum ofperr ofputil_decode_packet_out(struct ofputil_packet_out *,
                                       const struct ofp_packet_out *);
 struct ofpbuf *ofputil_encode_packet_out(const struct ofputil_packet_out *);
 
-/* OFPFF_* bits. */
-enum netdev_features ofputil_netdev_port_features_from_ofp10(ovs_be32 ofp10);
-ovs_be32 ofputil_netdev_port_features_to_ofp10(enum netdev_features);
+enum ofputil_port_config {
+    /* OpenFlow 1.0 and 1.1 share these values for these port config bits. */
+    OFPUTIL_PC_PORT_DOWN    = 1 << 0, /* Port is administratively down. */
+    OFPUTIL_PC_NO_RECV      = 1 << 2, /* Drop all packets received by port. */
+    OFPUTIL_PC_NO_FWD       = 1 << 5, /* Drop packets forwarded to port. */
+    OFPUTIL_PC_NO_PACKET_IN = 1 << 6, /* No send packet-in msgs for port. */
+    /* OpenFlow 1.0 only. */
+    OFPUTIL_PC_NO_STP       = 1 << 1, /* No 802.1D spanning tree for port. */
+    OFPUTIL_PC_NO_RECV_STP  = 1 << 3, /* Drop received 802.1D STP packets. */
+    OFPUTIL_PC_NO_FLOOD     = 1 << 4, /* Do not include port when flooding. */
+    /* There are no OpenFlow 1.1-only bits. */
+};
+
+enum ofputil_port_state {
+    /* OpenFlow 1.0 and 1.1 share this values for these port state bits. */
+    OFPUTIL_PS_LINK_DOWN   = 1 << 0, /* No physical link present. */
+    /* OpenFlow 1.1 only. */
+    OFPUTIL_PS_BLOCKED     = 1 << 1, /* Port is blocked */
+    OFPUTIL_PS_LIVE        = 1 << 2, /* Live for Fast Failover Group. */
+    /* OpenFlow 1.0 only. */
+    OFPUTIL_PS_STP_LISTEN  = 0 << 8, /* Not learning or relaying frames. */
+    OFPUTIL_PS_STP_LEARN   = 1 << 8, /* Learning but not relaying frames. */
+    OFPUTIL_PS_STP_FORWARD = 2 << 8, /* Learning and relaying frames. */
+    OFPUTIL_PS_STP_BLOCK   = 3 << 8, /* Not part of spanning tree. */
+    OFPUTIL_PS_STP_MASK    = 3 << 8  /* Bit mask for OFPPS10_STP_* values. */
+};
+
+/* Abstract ofp10_phy_port or ofp11_port. */
+struct ofputil_phy_port {
+    uint16_t port_no;
+    uint8_t hw_addr[OFP_ETH_ALEN];
+    char name[OFP_MAX_PORT_NAME_LEN];
+    enum ofputil_port_config config;
+    enum ofputil_port_state state;
+
+    /* NETDEV_F_* feature bitmasks. */
+    enum netdev_features curr;       /* Current features. */
+    enum netdev_features advertised; /* Features advertised by the port. */
+    enum netdev_features supported;  /* Features supported by the port. */
+    enum netdev_features peer;       /* Features advertised by peer. */
+
+    /* Speed. */
+    uint32_t curr_speed;        /* Current speed, in kbps. */
+    uint32_t max_speed;         /* Maximum supported speed, in kbps. */
+};
+
+enum ofputil_capabilities {
+    /* OpenFlow 1.0 and 1.1 share these values for these capabilities. */
+    OFPUTIL_C_FLOW_STATS     = 1 << 0,  /* Flow statistics. */
+    OFPUTIL_C_TABLE_STATS    = 1 << 1,  /* Table statistics. */
+    OFPUTIL_C_PORT_STATS     = 1 << 2,  /* Port statistics. */
+    OFPUTIL_C_IP_REASM       = 1 << 5,  /* Can reassemble IP fragments. */
+    OFPUTIL_C_QUEUE_STATS    = 1 << 6,  /* Queue statistics. */
+    OFPUTIL_C_ARP_MATCH_IP   = 1 << 7,  /* Match IP addresses in ARP pkts. */
+
+    /* OpenFlow 1.0 only. */
+    OFPUTIL_C_STP            = 1 << 3,  /* 802.1d spanning tree. */
+
+    /* OpenFlow 1.1 only. */
+    OFPUTIL_C_GROUP_STATS    = 1 << 4,  /* Group statistics. */
+};
+
+enum ofputil_action_bitmap {
+    OFPUTIL_A_OUTPUT         = 1 << 0,
+    OFPUTIL_A_SET_VLAN_VID   = 1 << 1,
+    OFPUTIL_A_SET_VLAN_PCP   = 1 << 2,
+    OFPUTIL_A_STRIP_VLAN     = 1 << 3,
+    OFPUTIL_A_SET_DL_SRC     = 1 << 4,
+    OFPUTIL_A_SET_DL_DST     = 1 << 5,
+    OFPUTIL_A_SET_NW_SRC     = 1 << 6,
+    OFPUTIL_A_SET_NW_DST     = 1 << 7,
+    OFPUTIL_A_SET_NW_ECN     = 1 << 8,
+    OFPUTIL_A_SET_NW_TOS     = 1 << 9,
+    OFPUTIL_A_SET_TP_SRC     = 1 << 10,
+    OFPUTIL_A_SET_TP_DST     = 1 << 11,
+    OFPUTIL_A_ENQUEUE        = 1 << 12,
+    OFPUTIL_A_COPY_TTL_OUT   = 1 << 13,
+    OFPUTIL_A_COPY_TTL_IN    = 1 << 14,
+    OFPUTIL_A_SET_MPLS_LABEL = 1 << 15,
+    OFPUTIL_A_SET_MPLS_TC    = 1 << 16,
+    OFPUTIL_A_SET_MPLS_TTL   = 1 << 17,
+    OFPUTIL_A_DEC_MPLS_TTL   = 1 << 18,
+    OFPUTIL_A_PUSH_VLAN      = 1 << 19,
+    OFPUTIL_A_POP_VLAN       = 1 << 20,
+    OFPUTIL_A_PUSH_MPLS      = 1 << 21,
+    OFPUTIL_A_POP_MPLS       = 1 << 22,
+    OFPUTIL_A_SET_QUEUE      = 1 << 23,
+    OFPUTIL_A_GROUP          = 1 << 24,
+    OFPUTIL_A_SET_NW_TTL     = 1 << 25,
+    OFPUTIL_A_DEC_NW_TTL     = 1 << 26,
+};
+
+/* Abstract ofp_switch_features. */
+struct ofputil_switch_features {
+    uint64_t datapath_id;       /* Datapath unique ID. */
+    uint32_t n_buffers;         /* Max packets buffered at once. */
+    uint8_t n_tables;           /* Number of tables supported by datapath. */
+    enum ofputil_capabilities capabilities;
+    enum ofputil_action_bitmap actions;
+};
+
+enum ofperr ofputil_decode_switch_features(const struct ofp_switch_features *,
+                                           struct ofputil_switch_features *,
+                                           struct ofpbuf *);
+int ofputil_pull_switch_features_port(struct ofpbuf *,
+                                      struct ofputil_phy_port *);
+size_t ofputil_count_phy_ports(const struct ofp_switch_features *);
+
+struct ofpbuf *ofputil_encode_switch_features(
+    const struct ofputil_switch_features *, enum ofputil_protocol,
+    ovs_be32 xid);
+void ofputil_put_switch_features_port(const struct ofputil_phy_port *,
+                                      struct ofpbuf *);
+
+/* Abstract ofp_port_status. */
+struct ofputil_port_status {
+    enum ofp_port_reason reason;
+    struct ofputil_phy_port desc;
+};
+
+enum ofperr ofputil_decode_port_status(const struct ofp_port_status *,
+                                       struct ofputil_port_status *);
+struct ofpbuf *ofputil_encode_port_status(const struct ofputil_port_status *,
+                                          enum ofputil_protocol);
+
+/* Abstract ofp_port_mod. */
+struct ofputil_port_mod {
+    uint16_t port_no;
+    uint8_t hw_addr[OFP_ETH_ALEN];
+    enum ofputil_port_config config;
+    enum ofputil_port_config mask;
+    enum netdev_features advertise;
+};
+
+enum ofperr ofputil_decode_port_mod(const struct ofp_header *,
+                                    struct ofputil_port_mod *);
+struct ofpbuf *ofputil_encode_port_mod(const struct ofputil_port_mod *,
+                                       enum ofputil_protocol);
 
 /* OpenFlow protocol utility functions. */
 void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **);
index ae0d3db..55b0306 100644 (file)
@@ -1236,21 +1236,21 @@ static void schedule_packet_in(struct ofconn *, struct ofputil_packet_in,
 /* Sends an OFPT_PORT_STATUS message with 'opp' and 'reason' to appropriate
  * controllers managed by 'mgr'. */
 void
-connmgr_send_port_status(struct connmgr *mgr, const struct ofp_phy_port *opp,
-                         uint8_t reason)
+connmgr_send_port_status(struct connmgr *mgr,
+                         const struct ofputil_phy_port *pp, uint8_t reason)
 {
     /* XXX Should limit the number of queued port status change messages. */
+    struct ofputil_port_status ps;
     struct ofconn *ofconn;
 
+    ps.reason = reason;
+    ps.desc = *pp;
     LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
         if (ofconn_receives_async_msg(ofconn, OAM_PORT_STATUS, reason)) {
-            struct ofp_port_status *ops;
-            struct ofpbuf *b;
+            struct ofpbuf *msg;
 
-            ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &b);
-            ops->reason = reason;
-            ops->desc = *opp;
-            ofconn_send(ofconn, b, NULL);
+            msg = ofputil_encode_port_status(&ps, ofconn->protocol);
+            ofconn_send(ofconn, msg, NULL);
         }
     }
 }
index 14698ab..2869ba7 100644 (file)
@@ -29,6 +29,7 @@ struct ofconn;
 struct ofopgroup;
 struct ofputil_flow_removed;
 struct ofputil_packet_in;
+struct ofputil_phy_port;
 struct sset;
 
 /* ofproto supports two kinds of OpenFlow connections:
@@ -123,8 +124,8 @@ void ofconn_remove_opgroup(struct ofconn *, struct list *,
                            const struct ofp_header *request, int error);
 
 /* Sending asynchronous messages. */
-void connmgr_send_port_status(struct connmgr *, const struct ofp_phy_port *,
-                              uint8_t reason);
+void connmgr_send_port_status(struct connmgr *,
+                              const struct ofputil_phy_port *, uint8_t reason);
 void connmgr_send_flow_removed(struct connmgr *,
                                const struct ofputil_flow_removed *);
 void connmgr_send_packet_in(struct connmgr *, const struct ofputil_packet_in *,
index fe10f12..457bbb7 100644 (file)
@@ -161,7 +161,7 @@ struct ofbundle {
     bool use_priority_tags;     /* Use 802.1p tag for frames in VLAN 0? */
 
     /* Status. */
-    bool floodable;             /* True if no port has OFPPC_NO_FLOOD set. */
+    bool floodable;          /* True if no port has OFPUTIL_PC_NO_FLOOD set. */
 
     /* Port mirroring info. */
     mirror_mask_t src_mirrors;  /* Mirrors triggered when packet received. */
@@ -914,21 +914,21 @@ flush(struct ofproto *ofproto_)
 
 static void
 get_features(struct ofproto *ofproto_ OVS_UNUSED,
-             bool *arp_match_ip, uint32_t *actions)
+             bool *arp_match_ip, enum ofputil_action_bitmap *actions)
 {
     *arp_match_ip = true;
-    *actions = ((1u << OFPAT10_OUTPUT) |
-                (1u << OFPAT10_SET_VLAN_VID) |
-                (1u << OFPAT10_SET_VLAN_PCP) |
-                (1u << OFPAT10_STRIP_VLAN) |
-                (1u << OFPAT10_SET_DL_SRC) |
-                (1u << OFPAT10_SET_DL_DST) |
-                (1u << OFPAT10_SET_NW_SRC) |
-                (1u << OFPAT10_SET_NW_DST) |
-                (1u << OFPAT10_SET_NW_TOS) |
-                (1u << OFPAT10_SET_TP_SRC) |
-                (1u << OFPAT10_SET_TP_DST) |
-                (1u << OFPAT10_ENQUEUE));
+    *actions = (OFPUTIL_A_OUTPUT |
+                OFPUTIL_A_SET_VLAN_VID |
+                OFPUTIL_A_SET_VLAN_PCP |
+                OFPUTIL_A_STRIP_VLAN |
+                OFPUTIL_A_SET_DL_SRC |
+                OFPUTIL_A_SET_DL_DST |
+                OFPUTIL_A_SET_NW_SRC |
+                OFPUTIL_A_SET_NW_DST |
+                OFPUTIL_A_SET_NW_TOS |
+                OFPUTIL_A_SET_TP_SRC |
+                OFPUTIL_A_SET_TP_DST |
+                OFPUTIL_A_ENQUEUE);
 }
 
 static void
@@ -1012,17 +1012,17 @@ port_modified(struct ofport *port_)
 }
 
 static void
-port_reconfigured(struct ofport *port_, ovs_be32 old_config)
+port_reconfigured(struct ofport *port_, enum ofputil_port_config old_config)
 {
     struct ofport_dpif *port = ofport_dpif_cast(port_);
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
-    ovs_be32 changed = old_config ^ port->up.opp.config;
+    enum ofputil_port_config changed = old_config ^ port->up.pp.config;
 
-    if (changed & htonl(OFPPC_NO_RECV | OFPPC_NO_RECV_STP |
-                        OFPPC_NO_FWD | OFPPC_NO_FLOOD)) {
+    if (changed & (OFPUTIL_PC_NO_RECV | OFPUTIL_PC_NO_RECV_STP |
+                   OFPUTIL_PC_NO_FWD | OFPUTIL_PC_NO_FLOOD)) {
         ofproto->need_revalidate = true;
 
-        if (changed & htonl(OFPPC_NO_FLOOD) && port->bundle) {
+        if (changed & OFPUTIL_PC_NO_FLOOD && port->bundle) {
             bundle_update(port->bundle);
         }
     }
@@ -1199,7 +1199,7 @@ update_stp_port_state(struct ofport_dpif *ofport)
 
     /* Update state. */
     if (ofport->stp_state != state) {
-        ovs_be32 of_state;
+        enum ofputil_port_state of_state;
         bool fwd_change;
 
         VLOG_DBG_RL(&rl, "port %s: STP state changed from %s to %s",
@@ -1223,12 +1223,12 @@ update_stp_port_state(struct ofport_dpif *ofport)
         }
 
         /* Update the STP state bits in the OpenFlow port description. */
-        of_state = (ofport->up.opp.state & htonl(~OFPPS_STP_MASK))
-                         | htonl(state == STP_LISTENING ? OFPPS_STP_LISTEN
-                               : state == STP_LEARNING ? OFPPS_STP_LEARN
-                               : state == STP_FORWARDING ? OFPPS_STP_FORWARD
-                               : state == STP_BLOCKING ?  OFPPS_STP_BLOCK
-                               : 0);
+        of_state = ofport->up.pp.state & ~OFPUTIL_PS_STP_MASK;
+        of_state |= (state == STP_LISTENING ? OFPUTIL_PS_STP_LISTEN
+                     : state == STP_LEARNING ? OFPUTIL_PS_STP_LEARN
+                     : state == STP_FORWARDING ? OFPUTIL_PS_STP_FORWARD
+                     : state == STP_BLOCKING ?  OFPUTIL_PS_STP_BLOCK
+                     : 0);
         ofproto_port_set_state(&ofport->up, of_state);
     }
 }
@@ -1516,7 +1516,8 @@ bundle_update(struct ofbundle *bundle)
 
     bundle->floodable = true;
     LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
-        if (port->up.opp.config & htonl(OFPPC_NO_FLOOD)) {
+        if (port->up.pp.config & OFPUTIL_PC_NO_FLOOD
+            || !stp_forward_in_state(port->stp_state)) {
             bundle->floodable = false;
             break;
         }
@@ -1563,7 +1564,8 @@ bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
 
         port->bundle = bundle;
         list_push_back(&bundle->ports, &port->bundle_node);
-        if (port->up.opp.config & htonl(OFPPC_NO_FLOOD)) {
+        if (port->up.pp.config & OFPUTIL_PC_NO_FLOOD
+            || !stp_forward_in_state(port->stp_state)) {
             bundle->floodable = false;
         }
     }
@@ -2210,7 +2212,7 @@ port_run(struct ofport_dpif *ofport)
             struct ofpbuf packet;
 
             ofpbuf_init(&packet, 0);
-            cfm_compose_ccm(ofport->cfm, &packet, ofport->up.opp.hw_addr);
+            cfm_compose_ccm(ofport->cfm, &packet, ofport->up.pp.hw_addr);
             send_packet(ofport, &packet);
             ofpbuf_uninit(&packet);
         }
@@ -2543,10 +2545,10 @@ handle_flow_miss(struct ofproto_dpif *ofproto, struct flow_miss *miss,
 
         rule = rule_dpif_lookup(ofproto, flow, 0);
         if (!rule) {
-            /* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */
+            /* Don't send a packet-in if OFPUTIL_PC_NO_PACKET_IN asserted. */
             struct ofport_dpif *port = get_ofp_port(ofproto, flow->in_port);
             if (port) {
-                if (port->up.opp.config & htonl(OFPPC_NO_PACKET_IN)) {
+                if (port->up.pp.config & OFPUTIL_PC_NO_PACKET_IN) {
                     COVERAGE_INC(ofproto_dpif_no_packet_in);
                     /* XXX install 'drop' flow entry */
                     return;
@@ -4333,7 +4335,7 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
     if (ofport) {
         struct priority_to_dscp *pdscp;
 
-        if (ofport->up.opp.config & htonl(OFPPC_NO_FWD)
+        if (ofport->up.pp.config & OFPUTIL_PC_NO_FWD
             || (check_stp && !stp_forward_in_state(ofport->stp_state))) {
             return;
         }
@@ -4456,7 +4458,7 @@ flood_packets(struct action_xlate_ctx *ctx, bool all)
 
         if (all) {
             compose_output_action__(ctx, ofp_port, false);
-        } else if (!(ofport->up.opp.config & htonl(OFPPC_NO_FLOOD))) {
+        } else if (!(ofport->up.pp.config & OFPUTIL_PC_NO_FLOOD)) {
             compose_output_action(ctx, ofp_port);
         }
     }
@@ -4761,9 +4763,9 @@ xlate_fin_timeout(struct action_xlate_ctx *ctx,
 static bool
 may_receive(const struct ofport_dpif *port, struct action_xlate_ctx *ctx)
 {
-    if (port->up.opp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp)
-                               ? htonl(OFPPC_NO_RECV_STP)
-                               : htonl(OFPPC_NO_RECV))) {
+    if (port->up.pp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp)
+                              ? OFPUTIL_PC_NO_RECV_STP
+                              : OFPUTIL_PC_NO_RECV)) {
         return false;
     }
 
index 9ba62de..04c156a 100644 (file)
@@ -25,6 +25,7 @@
 #include "heap.h"
 #include "list.h"
 #include "ofp-errors.h"
+#include "ofp-util.h"
 #include "shash.h"
 #include "timeval.h"
 
@@ -95,13 +96,13 @@ struct ofport {
     struct ofproto *ofproto;    /* The ofproto that contains this port. */
     struct hmap_node hmap_node; /* In struct ofproto's "ports" hmap. */
     struct netdev *netdev;
-    struct ofp_phy_port opp;
+    struct ofputil_phy_port pp;
     uint16_t ofp_port;          /* OpenFlow port number. */
     unsigned int change_seq;
     int mtu;
 };
 
-void ofproto_port_set_state(struct ofport *, ovs_be32 state);
+void ofproto_port_set_state(struct ofport *, enum ofputil_port_state);
 
 enum oftable_flags {
     OFTABLE_HIDDEN = 1 << 0,   /* Hide from most OpenFlow operations. */
@@ -411,14 +412,10 @@ struct ofproto_class {
      * otherwise.
      *
      * The implementation should store in '*actions' a bitmap of the supported
-     * OpenFlow actions: the bit with value (1 << n) should be set to 1 if the
-     * implementation supports the action with value 'n', and to 0 otherwise.
-     * For example, if the implementation supports the OFPAT_OUTPUT and
-     * OFPAT_ENQUEUE actions, but no others, it would set '*actions' to (1 <<
-     * OFPAT_OUTPUT) | (1 << OFPAT_ENQUEUE).  Vendor actions are not included
-     * in '*actions'. */
+     * OpenFlow actions.  Vendor actions are not included in '*actions'. */
     void (*get_features)(struct ofproto *ofproto,
-                         bool *arp_match_ip, uint32_t *actions);
+                         bool *arp_match_ip,
+                         enum ofputil_action_bitmap *actions);
 
     /* Helper for the OpenFlow OFPST_TABLE statistics request.
      *
@@ -504,15 +501,16 @@ struct ofproto_class {
      * function may use a null pointer. */
     void (*port_modified)(struct ofport *ofport);
 
-    /* Called after an OpenFlow OFPT_PORT_MOD request changes a port's
-     * configuration.  'ofport->opp.config' contains the new configuration.
-     * 'old_config' contains the previous configuration.
+    /* Called after an OpenFlow request changes a port's configuration.
+     * 'ofport->pp.config' contains the new configuration.  'old_config'
+     * contains the previous configuration.
      *
-     * The caller implements OFPPC_PORT_DOWN using netdev functions to turn
-     * NETDEV_UP on and off, so this function doesn't have to do anything for
-     * that bit (and it won't be called if that is the only bit that
+     * The caller implements OFPUTIL_PC_PORT_DOWN using netdev functions to
+     * turn NETDEV_UP on and off, so this function doesn't have to do anything
+     * for that bit (and it won't be called if that is the only bit that
      * changes). */
-    void (*port_reconfigured)(struct ofport *ofport, ovs_be32 old_config);
+    void (*port_reconfigured)(struct ofport *ofport,
+                              enum ofputil_port_config old_config);
 
     /* Looks up a port named 'devname' in 'ofproto'.  On success, initializes
      * '*port' appropriately.
index f9ed23e..d03bd9b 100644 (file)
@@ -1400,9 +1400,9 @@ reinit_ports(struct ofproto *p)
 /* Opens and returns a netdev for 'ofproto_port', or a null pointer if the
  * netdev cannot be opened.  On success, also fills in 'opp'.  */
 static struct netdev *
-ofport_open(const struct ofproto_port *ofproto_port, struct ofp_phy_port *opp)
+ofport_open(const struct ofproto_port *ofproto_port,
+            struct ofputil_phy_port *pp)
 {
-    enum netdev_features curr, advertised, supported, peer;
     enum netdev_flags flags;
     struct netdev *netdev;
     int error;
@@ -1416,36 +1416,36 @@ ofport_open(const struct ofproto_port *ofproto_port, struct ofp_phy_port *opp)
         return NULL;
     }
 
+    pp->port_no = ofproto_port->ofp_port;
+    netdev_get_etheraddr(netdev, pp->hw_addr);
+    ovs_strlcpy(pp->name, ofproto_port->name, sizeof pp->name);
     netdev_get_flags(netdev, &flags);
-    netdev_get_features(netdev, &curr, &advertised, &supported, &peer);
-
-    opp->port_no = htons(ofproto_port->ofp_port);
-    netdev_get_etheraddr(netdev, opp->hw_addr);
-    ovs_strzcpy(opp->name, ofproto_port->name, sizeof opp->name);
-    opp->config = flags & NETDEV_UP ? 0 : htonl(OFPPC_PORT_DOWN);
-    opp->state = netdev_get_carrier(netdev) ? 0 : htonl(OFPPS_LINK_DOWN);
-    opp->curr = ofputil_netdev_port_features_to_ofp10(curr);
-    opp->advertised = ofputil_netdev_port_features_to_ofp10(advertised);
-    opp->supported = ofputil_netdev_port_features_to_ofp10(supported);
-    opp->peer = ofputil_netdev_port_features_to_ofp10(peer);
+    pp->config = flags & NETDEV_UP ? 0 : OFPUTIL_PC_PORT_DOWN;
+    pp->state = netdev_get_carrier(netdev) ? 0 : OFPUTIL_PS_LINK_DOWN;
+    netdev_get_features(netdev, &pp->curr, &pp->advertised,
+                        &pp->supported, &pp->peer);
+    pp->curr_speed = netdev_features_to_bps(pp->curr);
+    pp->max_speed = netdev_features_to_bps(pp->supported);
 
     return netdev;
 }
 
 /* Returns true if most fields of 'a' and 'b' are equal.  Differences in name,
- * port number, and 'config' bits other than OFPPC_PORT_DOWN are
+ * port number, and 'config' bits other than OFPUTIL_PS_LINK_DOWN are
  * disregarded. */
 static bool
-ofport_equal(const struct ofp_phy_port *a, const struct ofp_phy_port *b)
+ofport_equal(const struct ofputil_phy_port *a,
+             const struct ofputil_phy_port *b)
 {
-    BUILD_ASSERT_DECL(sizeof *a == 48); /* Detect ofp_phy_port changes. */
-    return (!memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr)
+    return (eth_addr_equals(a->hw_addr, b->hw_addr)
             && a->state == b->state
-            && !((a->config ^ b->config) & htonl(OFPPC_PORT_DOWN))
+            && !((a->config ^ b->config) & OFPUTIL_PC_PORT_DOWN)
             && a->curr == b->curr
             && a->advertised == b->advertised
             && a->supported == b->supported
-            && a->peer == b->peer);
+            && a->peer == b->peer
+            && a->curr_speed == b->curr_speed
+            && a->max_speed == b->max_speed);
 }
 
 /* Adds an ofport to 'p' initialized based on the given 'netdev' and 'opp'.
@@ -1453,7 +1453,7 @@ ofport_equal(const struct ofp_phy_port *a, const struct ofp_phy_port *b)
  * one with the same name or port number). */
 static void
 ofport_install(struct ofproto *p,
-               struct netdev *netdev, const struct ofp_phy_port *opp)
+               struct netdev *netdev, const struct ofputil_phy_port *pp)
 {
     const char *netdev_name = netdev_get_name(netdev);
     struct ofport *ofport;
@@ -1469,8 +1469,8 @@ ofport_install(struct ofproto *p,
     ofport->ofproto = p;
     ofport->netdev = netdev;
     ofport->change_seq = netdev_change_seq(netdev);
-    ofport->opp = *opp;
-    ofport->ofp_port = ntohs(opp->port_no);
+    ofport->pp = *pp;
+    ofport->ofp_port = pp->port_no;
 
     /* Add port to 'p'. */
     hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->ofp_port, 0));
@@ -1488,7 +1488,7 @@ ofport_install(struct ofproto *p,
     if (error) {
         goto error;
     }
-    connmgr_send_port_status(p->connmgr, opp, OFPPR_ADD);
+    connmgr_send_port_status(p->connmgr, pp, OFPPR_ADD);
     return;
 
 error:
@@ -1505,7 +1505,7 @@ error:
 static void
 ofport_remove(struct ofport *ofport)
 {
-    connmgr_send_port_status(ofport->ofproto->connmgr, &ofport->opp,
+    connmgr_send_port_status(ofport->ofproto->connmgr, &ofport->pp,
                              OFPPR_DELETE);
     ofport_destroy(ofport);
 }
@@ -1521,32 +1521,34 @@ ofport_remove_with_name(struct ofproto *ofproto, const char *name)
     }
 }
 
-/* Updates 'port' with new 'opp' description.
+/* Updates 'port' with new 'pp' description.
  *
  * Does not handle a name or port number change.  The caller must implement
  * such a change as a delete followed by an add.  */
 static void
-ofport_modified(struct ofport *port, struct ofp_phy_port *opp)
+ofport_modified(struct ofport *port, struct ofputil_phy_port *pp)
 {
-    memcpy(port->opp.hw_addr, opp->hw_addr, ETH_ADDR_LEN);
-    port->opp.config = ((port->opp.config & ~htonl(OFPPC_PORT_DOWN))
-                        | (opp->config & htonl(OFPPC_PORT_DOWN)));
-    port->opp.state = opp->state;
-    port->opp.curr = opp->curr;
-    port->opp.advertised = opp->advertised;
-    port->opp.supported = opp->supported;
-    port->opp.peer = opp->peer;
+    memcpy(port->pp.hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+    port->pp.config = ((port->pp.config & ~OFPUTIL_PC_PORT_DOWN)
+                        | (pp->config & OFPUTIL_PC_PORT_DOWN));
+    port->pp.state = pp->state;
+    port->pp.curr = pp->curr;
+    port->pp.advertised = pp->advertised;
+    port->pp.supported = pp->supported;
+    port->pp.peer = pp->peer;
+    port->pp.curr_speed = pp->curr_speed;
+    port->pp.max_speed = pp->max_speed;
 
-    connmgr_send_port_status(port->ofproto->connmgr, &port->opp, OFPPR_MODIFY);
+    connmgr_send_port_status(port->ofproto->connmgr, &port->pp, OFPPR_MODIFY);
 }
 
 /* Update OpenFlow 'state' in 'port' and notify controller. */
 void
-ofproto_port_set_state(struct ofport *port, ovs_be32 state)
+ofproto_port_set_state(struct ofport *port, enum ofputil_port_state state)
 {
-    if (port->opp.state != state) {
-        port->opp.state = state;
-        connmgr_send_port_status(port->ofproto->connmgr, &port->opp,
+    if (port->pp.state != state) {
+        port->pp.state = state;
+        connmgr_send_port_status(port->ofproto->connmgr, &port->pp,
                                  OFPPR_MODIFY);
     }
 }
@@ -1627,7 +1629,7 @@ static void
 update_port(struct ofproto *ofproto, const char *name)
 {
     struct ofproto_port ofproto_port;
-    struct ofp_phy_port opp;
+    struct ofputil_phy_port pp;
     struct netdev *netdev;
     struct ofport *port;
 
@@ -1635,7 +1637,7 @@ update_port(struct ofproto *ofproto, const char *name)
 
     /* Fetch 'name''s location and properties from the datapath. */
     netdev = (!ofproto_port_query_by_name(ofproto, name, &ofproto_port)
-              ? ofport_open(&ofproto_port, &opp)
+              ? ofport_open(&ofproto_port, &pp)
               : NULL);
     if (netdev) {
         port = ofproto_get_port(ofproto, ofproto_port.ofp_port);
@@ -1644,8 +1646,8 @@ update_port(struct ofproto *ofproto, const char *name)
             int dev_mtu;
 
             /* 'name' hasn't changed location.  Any properties changed? */
-            if (!ofport_equal(&port->opp, &opp)) {
-                ofport_modified(port, &opp);
+            if (!ofport_equal(&port->pp, &pp)) {
+                ofport_modified(port, &pp);
             }
 
             /* If this is a non-internal port and the MTU changed, check
@@ -1676,7 +1678,7 @@ update_port(struct ofproto *ofproto, const char *name)
                 ofport_remove(port);
             }
             ofport_remove_with_name(ofproto, name);
-            ofport_install(ofproto, netdev, &opp);
+            ofport_install(ofproto, netdev, &pp);
         }
     } else {
         /* Any port named 'name' is gone now. */
@@ -1700,12 +1702,12 @@ init_ports(struct ofproto *p)
             VLOG_WARN_RL(&rl, "ignoring duplicate device %s in datapath",
                          ofproto_port.name);
         } else {
-            struct ofp_phy_port opp;
+            struct ofputil_phy_port pp;
             struct netdev *netdev;
 
-            netdev = ofport_open(&ofproto_port, &opp);
+            netdev = ofport_open(&ofproto_port, &pp);
             if (netdev) {
-                ofport_install(p, netdev, &opp);
+                ofport_install(p, netdev, &pp);
             }
         }
     }
@@ -1857,31 +1859,31 @@ static enum ofperr
 handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
-    struct ofp_switch_features *osf;
-    struct ofpbuf *buf;
+    struct ofputil_switch_features features;
     struct ofport *port;
     bool arp_match_ip;
-    uint32_t actions;
+    struct ofpbuf *b;
 
-    ofproto->ofproto_class->get_features(ofproto, &arp_match_ip, &actions);
-    assert(actions & (1 << OFPAT10_OUTPUT)); /* sanity check */
+    ofproto->ofproto_class->get_features(ofproto, &arp_match_ip,
+                                         &features.actions);
+    assert(features.actions & OFPUTIL_A_OUTPUT); /* sanity check */
 
-    osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, oh->xid, &buf);
-    osf->datapath_id = htonll(ofproto->datapath_id);
-    osf->n_buffers = htonl(pktbuf_capacity());
-    osf->n_tables = ofproto->n_tables;
-    osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS |
-                              OFPC_PORT_STATS | OFPC_QUEUE_STATS);
+    features.datapath_id = ofproto->datapath_id;
+    features.n_buffers = pktbuf_capacity();
+    features.n_tables = ofproto->n_tables;
+    features.capabilities = (OFPUTIL_C_FLOW_STATS | OFPUTIL_C_TABLE_STATS |
+                             OFPUTIL_C_PORT_STATS | OFPUTIL_C_QUEUE_STATS);
     if (arp_match_ip) {
-        osf->capabilities |= htonl(OFPC_ARP_MATCH_IP);
+        features.capabilities |= OFPUTIL_C_ARP_MATCH_IP;
     }
-    osf->actions = htonl(actions);
 
+    b = ofputil_encode_switch_features(&features, ofconn_get_protocol(ofconn),
+                                       oh->xid);
     HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
-        ofpbuf_put(buf, &port->opp, sizeof port->opp);
+        ofputil_put_switch_features_port(&port->pp, b);
     }
 
-    ofconn_send_reply(ofconn, buf);
+    ofconn_send_reply(ofconn, b);
     return 0;
 }
 
@@ -1995,23 +1997,25 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo)
 }
 
 static void
-update_port_config(struct ofport *port, ovs_be32 config, ovs_be32 mask)
+update_port_config(struct ofport *port,
+                   enum ofputil_port_config config,
+                   enum ofputil_port_config mask)
 {
-    ovs_be32 old_config = port->opp.config;
+    enum ofputil_port_config old_config = port->pp.config;
+    enum ofputil_port_config toggle;
 
-    mask &= config ^ port->opp.config;
-    if (mask & htonl(OFPPC_PORT_DOWN)) {
-        if (config & htonl(OFPPC_PORT_DOWN)) {
+    toggle = (config ^ port->pp.config) & mask;
+    if (toggle & OFPUTIL_PC_PORT_DOWN) {
+        if (config & OFPUTIL_PC_PORT_DOWN) {
             netdev_turn_flags_off(port->netdev, NETDEV_UP, true);
         } else {
             netdev_turn_flags_on(port->netdev, NETDEV_UP, true);
         }
+        toggle &= ~OFPUTIL_PC_PORT_DOWN;
     }
 
-    port->opp.config ^= mask & (htonl(OFPPC_NO_RECV | OFPPC_NO_RECV_STP |
-                                      OFPPC_NO_FLOOD | OFPPC_NO_FWD |
-                                      OFPPC_NO_PACKET_IN));
-    if (port->opp.config != old_config) {
+    port->pp.config ^= toggle;
+    if (port->pp.config != old_config) {
         port->ofproto->ofproto_class->port_reconfigured(port, old_config);
     }
 }
@@ -2020,27 +2024,29 @@ static enum ofperr
 handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
-    const struct ofp_port_mod *opm = (const struct ofp_port_mod *) oh;
+    struct ofputil_port_mod pm;
     struct ofport *port;
-    int error;
+    enum ofperr error;
 
     error = reject_slave_controller(ofconn);
     if (error) {
         return error;
     }
 
-    port = ofproto_get_port(p, ntohs(opm->port_no));
+    error = ofputil_decode_port_mod(oh, &pm);
+    if (error) {
+        return error;
+    }
+
+    port = ofproto_get_port(p, pm.port_no);
     if (!port) {
         return OFPERR_OFPPMFC_BAD_PORT;
-    } else if (memcmp(port->opp.hw_addr, opm->hw_addr, OFP_ETH_ALEN)) {
+    } else if (!eth_addr_equals(port->pp.hw_addr, pm.hw_addr)) {
         return OFPERR_OFPPMFC_BAD_HW_ADDR;
     } else {
-        update_port_config(port, opm->config, opm->mask);
-        if (opm->advertise) {
-            enum netdev_features adv;
-
-            adv = ofputil_netdev_port_features_from_ofp10(opm->advertise);
-            netdev_set_advertisements(port->netdev, adv);
+        update_port_config(port, pm.config, pm.mask);
+        if (pm.advertise) {
+            netdev_set_advertisements(port->netdev, pm.advertise);
         }
     }
     return 0;
@@ -2115,7 +2121,7 @@ append_port_stat(struct ofport *port, struct list *replies)
     ofproto_port_get_stats(port, &stats);
 
     ops = ofputil_append_stats_reply(sizeof *ops, replies);
-    ops->port_no = port->opp.port_no;
+    ops->port_no = htons(port->pp.port_no);
     memset(ops->pad, 0, sizeof ops->pad);
     put_32aligned_be64(&ops->rx_packets, htonll(stats.rx_packets));
     put_32aligned_be64(&ops->tx_packets, htonll(stats.tx_packets));
@@ -2536,7 +2542,7 @@ put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
     struct ofp_queue_stats *reply;
 
     reply = ofputil_append_stats_reply(sizeof *reply, &cbdata->replies);
-    reply->port_no = cbdata->ofport->opp.port_no;
+    reply->port_no = htons(cbdata->ofport->pp.port_no);
     memset(reply->pad, 0, sizeof reply->pad);
     reply->queue_id = htonl(queue_id);
     put_32aligned_be64(&reply->tx_bytes, htonll(stats->tx_bytes));
index 46b1617..9ac1d23 100644 (file)
@@ -154,7 +154,7 @@ OFPT_FEATURES_REQUEST (xid=0x1):
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPT_FEATURES_REPLY])
+AT_SETUP([OFPT_FEATURES_REPLY - OF1.0])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 01 06 00 e0 00 00 00 01 00 00 50 54 00 00 00 01 \
@@ -172,34 +172,39 @@ ff fe 50 54 00 00 00 01 62 72 30 00 00 00 00 00 \
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
 00 00 02 08 00 00 02 8f 00 00 02 8f 00 00 00 00 \
 "], [0], [dnl
-OFPT_FEATURES_REPLY (xid=0x1): ver:0x1, dpid:0000505400000001
+OFPT_FEATURES_REPLY (xid=0x1): dpid:0000505400000001
 n_tables:2, n_buffers:256
-features: capabilities:0x87, actions:0xfff
+capabilities: FLOW_STATS TABLE_STATS PORT_STATS ARP_MATCH_IP
+actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
  1(eth1): addr:50:54:00:00:00:02
      config:     0
      state:      0
      current:    100MB-FD AUTO_NEG
      advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
      supported:  10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
+     speed: 100 Mbps now, 100 Mbps max
  2(eth2): addr:50:54:00:00:00:03
      config:     0
      state:      0
      current:    100MB-FD AUTO_NEG
      advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
      supported:  10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
+     speed: 100 Mbps now, 100 Mbps max
  3(eth0): addr:50:54:00:00:00:01
      config:     0
      state:      0
      current:    100MB-FD AUTO_NEG
      advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
      supported:  10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
+     speed: 100 Mbps now, 100 Mbps max
  LOCAL(br0): addr:50:54:00:00:00:01
      config:     PORT_DOWN
      state:      LINK_DOWN
+     speed: 100 Mbps now, 100 Mbps max
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPT_FEATURES_REPLY cut off mid-port])
+AT_SETUP([OFPT_FEATURES_REPLY cut off mid-port - OF1.0])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 01 06 00 dc 00 00 00 01 00 00 50 54 00 00 00 01 \
@@ -238,6 +243,67 @@ received OFPT_FEATURES_REPLY with incorrect length 220 (must be exactly 32 bytes
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_FEATURES_REPLY - OF1.1])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 06 00 a0 00 00 00 01 00 00 50 54 00 00 00 01 \
+00 00 01 00 02 00 00 00 00 00 00 87 00 00 ff ff \
+ff ff ff fe 00 00 00 00 50 54 00 00 00 01 00 00 \
+62 72 30 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 01 86 a0 00 01 86 a0 \
+00 00 00 03 00 00 00 00 50 54 00 00 00 01 00 00 \
+65 74 68 30 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 20 08 00 00 28 0f \
+00 00 28 0f 00 00 00 00 00 01 86 a0 00 01 86 a0 \
+"], [0], [dnl
+OFPT_FEATURES_REPLY (OF1.1) (xid=0x1): dpid:0000505400000001
+n_tables:2, n_buffers:256
+capabilities: FLOW_STATS TABLE_STATS PORT_STATS ARP_MATCH_IP
+actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_ECN SET_NW_TOS SET_TP_SRC SET_TP_DST COPY_TTL_OUT COPY_TTL_IN SET_MPLS_LABEL SET_MPLS_TC SET_MPLS_TTL
+ 3(eth0): addr:50:54:00:00:00:01
+     config:     0
+     state:      0
+     current:    100MB-FD AUTO_NEG
+     advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
+     supported:  10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
+     speed: 100 Mbps now, 100 Mbps max
+ LOCAL(br0): addr:50:54:00:00:00:01
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 100 Mbps now, 100 Mbps max
+])
+AT_CLEANUP
+
+AT_SETUP([OFPT_FEATURES_REPLY cut off mid-port - OF1.1])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 06 00 90 00 00 00 01 00 00 50 54 00 00 00 01 \
+00 00 01 00 02 00 00 00 00 00 00 87 00 00 ff ff \
+ff ff ff fe 00 00 00 00 50 54 00 00 00 01 00 00 \
+62 72 30 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 01 86 a0 00 01 86 a0 \
+00 00 00 03 00 00 00 00 50 54 00 00 00 01 00 00 \
+65 74 68 30 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 20 08 00 00 28 0f \
+"], [0], [dnl
+***decode error: OFPBRC_BAD_LEN***
+00000000  02 06 00 90 00 00 00 01-00 00 50 54 00 00 00 01 |..........PT....|
+00000010  00 00 01 00 02 00 00 00-00 00 00 87 00 00 ff ff |................|
+00000020  ff ff ff fe 00 00 00 00-50 54 00 00 00 01 00 00 |........PT......|
+00000030  62 72 30 00 00 00 00 00-00 00 00 00 00 00 00 00 |br0.............|
+00000040  00 00 00 01 00 00 00 01-00 00 00 00 00 00 00 00 |................|
+00000050  00 00 00 00 00 00 00 00-00 01 86 a0 00 01 86 a0 |................|
+00000060  00 00 00 03 00 00 00 00-50 54 00 00 00 01 00 00 |........PT......|
+00000070  65 74 68 30 00 00 00 00-00 00 00 00 00 00 00 00 |eth0............|
+00000080  00 00 00 00 00 00 00 00-00 00 20 08 00 00 28 0f |.......... ...@{:@.|
+], [stderr])
+AT_CHECK([sed 's/.*|//' stderr], [0], [dnl
+received OFPT_FEATURES_REPLY with incorrect length 144 (must be exactly 32 bytes or longer by an integer multiple of 64 bytes)
+])
+AT_CLEANUP
+
 AT_SETUP([OFPT_GET_CONFIG_REQUEST])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print '0107000800000001'], [0], [dnl
@@ -288,7 +354,7 @@ OFPT_FLOW_REMOVED (xid=0x0): priority=65535,arp,in_port=3,vlan_tci=0x0000,dl_src
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPT_PORT_STATUS])
+AT_SETUP([OFPT_PORT_STATUS - OF1.0])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 01 0c 00 40 00 00 00 00 02 00 00 00 00 00 00 00 \
@@ -302,6 +368,26 @@ OFPT_PORT_STATUS (xid=0x0): MOD: 3(eth0): addr:50:54:00:00:00:01
      current:    100MB-FD AUTO_NEG
      advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
      supported:  10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
+     speed: 100 Mbps now, 100 Mbps max
+])
+AT_CLEANUP
+
+AT_SETUP([OFPT_PORT_STATUS - OF1.1])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 0c 00 50 00 00 00 00 02 00 00 00 00 00 00 00 \
+00 00 00 03 00 00 00 00 50 54 00 00 00 01 00 00 \
+65 74 68 30 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 20 08 00 00 28 0f \
+00 00 28 0f 00 00 00 00 00 01 86 a0 00 01 86 a0 \
+"], [0], [dnl
+OFPT_PORT_STATUS (OF1.1) (xid=0x0): MOD: 3(eth0): addr:50:54:00:00:00:01
+     config:     0
+     state:      0
+     current:    100MB-FD AUTO_NEG
+     advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
+     supported:  10MB-HD 10MB-FD 100MB-HD 100MB-FD COPPER AUTO_NEG
+     speed: 100 Mbps now, 100 Mbps max
 ])
 AT_CLEANUP
 
@@ -355,13 +441,29 @@ ofp_util|INFO|post: priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPT_PORT_MOD])
+AT_SETUP([OFPT_PORT_MOD - OF1.0])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 01 0f 00 20 00 00 00 03 00 03 50 54 00 00 00 01 \
 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
 " 3], [0], [dnl
-OFPT_PORT_MOD (xid=0x3):port: 3: addr:50:54:00:00:00:01, config: 0x1, mask:0x1
+OFPT_PORT_MOD (xid=0x3):port: 3: addr:50:54:00:00:00:01
+     config: PORT_DOWN
+     mask:   PORT_DOWN
+     advertise: UNCHANGED
+])
+AT_CLEANUP
+
+AT_SETUP([OFPT_PORT_MOD - OF1.1])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 10 00 28 00 00 00 03 00 00 00 03 00 00 00 00 \
+50 54 00 00 00 01 00 00 00 00 00 01 00 00 00 01 \
+00 00 00 00 00 00 00 00 \
+" 3], [0], [dnl
+OFPT_PORT_MOD (OF1.1) (xid=0x3):port: 3: addr:50:54:00:00:00:01
+     config: PORT_DOWN
+     mask:   PORT_DOWN
      advertise: UNCHANGED
 ])
 AT_CLEANUP
index 0bc997c..b39de70 100644 (file)
@@ -10,12 +10,14 @@ AT_SETUP([ofproto - feature request, config request])
 OVS_VSWITCHD_START
 AT_CHECK([ovs-ofctl -vANY:ANY:WARN show br0], [0], [stdout])
 AT_CHECK([STRIP_XIDS stdout], [0], [dnl
-OFPT_FEATURES_REPLY: ver:0x1, dpid:fedcba9876543210
+OFPT_FEATURES_REPLY: dpid:fedcba9876543210
 n_tables:255, n_buffers:256
-features: capabilities:0xc7, actions:0xfff
+capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
+actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
  LOCAL(br0): addr:aa:55:aa:55:00:00
      config:     PORT_DOWN
      state:      LINK_DOWN
+     speed: 100 Mbps now, 100 Mbps max
 OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
 ])
 OVS_VSWITCHD_STOP
@@ -58,12 +60,14 @@ do
     AT_CHECK([ovs-ofctl -vANY:ANY:WARN mod-port br0 br0 $command])
     AT_CHECK([ovs-ofctl -vANY:ANY:WARN show br0], [0], [stdout])
     AT_CHECK_UNQUOTED([STRIP_XIDS stdout], [0], [dnl
-OFPT_FEATURES_REPLY: ver:0x1, dpid:fedcba9876543210
+OFPT_FEATURES_REPLY: dpid:fedcba9876543210
 n_tables:255, n_buffers:256
-features: capabilities:0xc7, actions:0xfff
+capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
+actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
  LOCAL(br0): addr:aa:55:aa:55:00:00
      config:     $config
      state:      $state
+     speed: 100 Mbps now, 100 Mbps max
 OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
 ])
 done
@@ -459,7 +463,8 @@ priority:0,tunnel:0,in_port:0000,tci(0) mac(00:26:b9:8c:b0:f9->00:25:83:df:b4:00
     if test X"$1" = X"OFPPR_ADD"; then shift;
         echo >>expout "OFPT_PORT_STATUS: ADD: 1(test): addr:aa:55:aa:55:00:0x
      config:     PORT_DOWN
-     state:      LINK_DOWN"
+     state:      LINK_DOWN
+     speed: 100 Mbps now, 100 Mbps max"
     fi
 
     # OFPT_PORT_STATUS, OFPPR_DELETE
@@ -467,7 +472,8 @@ priority:0,tunnel:0,in_port:0000,tci(0) mac(00:26:b9:8c:b0:f9->00:25:83:df:b4:00
     if test X"$1" = X"OFPPR_DELETE"; then shift;
         echo >>expout "OFPT_PORT_STATUS: DEL: 1(test): addr:aa:55:aa:55:00:0x
      config:     PORT_DOWN
-     state:      LINK_DOWN"
+     state:      LINK_DOWN
+     speed: 100 Mbps now, 100 Mbps max"
     fi
 
     # OFPT_FLOW_REMOVED, OFPRR_DELETE
index d81e295..fcbbf21 100644 (file)
@@ -510,19 +510,20 @@ do_dump_tables(int argc OVS_UNUSED, char *argv[])
     dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
 }
 
-/* Opens a connection to 'vconn_name', fetches the ofp_phy_port structure for
+/* Opens a connection to 'vconn_name', fetches the port structure for
  * 'port_name' (which may be a port name or number), and copies it into
  * '*oppp'. */
 static void
-fetch_ofp_phy_port(const char *vconn_name, const char *port_name,
-                   struct ofp_phy_port *oppp)
+fetch_ofputil_phy_port(const char *vconn_name, const char *port_name,
+                       struct ofputil_phy_port *pp)
 {
+    struct ofputil_switch_features features;
+    const struct ofp_switch_features *osf;
     struct ofpbuf *request, *reply;
-    struct ofp_switch_features *osf;
     unsigned int port_no;
     struct vconn *vconn;
-    int n_ports;
-    int port_idx;
+    enum ofperr error;
+    struct ofpbuf b;
 
     /* Try to interpret the argument as a port number. */
     if (!str_to_uint(port_name, 10, &port_no)) {
@@ -539,15 +540,16 @@ fetch_ofp_phy_port(const char *vconn_name, const char *port_name,
         ovs_fatal(0, "%s: received too-short features reply (only %zu bytes)",
                   vconn_name, reply->size);
     }
-    n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
-
-    for (port_idx = 0; port_idx < n_ports; port_idx++) {
-        const struct ofp_phy_port *opp = &osf->ports[port_idx];
+    error = ofputil_decode_switch_features(osf, &features, &b);
+    if (error) {
+        ovs_fatal(0, "%s: failed to decode features reply (%s)",
+                  vconn_name, ofperr_to_string(error));
+    }
 
+    while (!ofputil_pull_switch_features_port(&b, pp)) {
         if (port_no != UINT_MAX
-            ? htons(port_no) == opp->port_no
-            : !strncmp(opp->name, port_name, sizeof opp->name)) {
-            *oppp = *opp;
+            ? port_no == pp->port_no
+            : !strcmp(pp->name, port_name)) {
             ofpbuf_delete(reply);
             vconn_close(vconn);
             return;
@@ -566,10 +568,10 @@ str_to_port_no(const char *vconn_name, const char *port_name)
     if (str_to_uint(port_name, 10, &port_no)) {
         return port_no;
     } else {
-        struct ofp_phy_port opp;
+        struct ofputil_phy_port pp;
 
-        fetch_ofp_phy_port(vconn_name, port_name, &opp);
-        return ntohs(opp.port_no);
+        fetch_ofputil_phy_port(vconn_name, port_name, &pp);
+        return pp.port_no;
     }
 }
 
@@ -1141,42 +1143,40 @@ do_packet_out(int argc, char *argv[])
 static void
 do_mod_port(int argc OVS_UNUSED, char *argv[])
 {
-    struct ofp_port_mod *opm;
-    struct ofp_phy_port opp;
-    struct ofpbuf *request;
+    enum ofputil_protocol protocol;
+    struct ofputil_port_mod pm;
+    struct ofputil_phy_port pp;
     struct vconn *vconn;
 
-    fetch_ofp_phy_port(argv[1], argv[2], &opp);
+    fetch_ofputil_phy_port(argv[1], argv[2], &pp);
 
-    opm = make_openflow(sizeof(struct ofp_port_mod), OFPT10_PORT_MOD,
-                        &request);
-    opm->port_no = opp.port_no;
-    memcpy(opm->hw_addr, opp.hw_addr, sizeof opm->hw_addr);
-    opm->config = htonl(0);
-    opm->mask = htonl(0);
-    opm->advertise = htonl(0);
+    pm.port_no = pp.port_no;
+    memcpy(pm.hw_addr, pp.hw_addr, ETH_ADDR_LEN);
+    pm.config = 0;
+    pm.mask = 0;
+    pm.advertise = 0;
 
     if (!strcasecmp(argv[3], "up")) {
-        opm->mask |= htonl(OFPPC_PORT_DOWN);
+        pm.mask |= OFPUTIL_PC_PORT_DOWN;
     } else if (!strcasecmp(argv[3], "down")) {
-        opm->mask |= htonl(OFPPC_PORT_DOWN);
-        opm->config |= htonl(OFPPC_PORT_DOWN);
+        pm.mask |= OFPUTIL_PC_PORT_DOWN;
+        pm.config |= OFPUTIL_PC_PORT_DOWN;
     } else if (!strcasecmp(argv[3], "flood")) {
-        opm->mask |= htonl(OFPPC_NO_FLOOD);
+        pm.mask |= OFPUTIL_PC_NO_FLOOD;
     } else if (!strcasecmp(argv[3], "noflood")) {
-        opm->mask |= htonl(OFPPC_NO_FLOOD);
-        opm->config |= htonl(OFPPC_NO_FLOOD);
+        pm.mask |= OFPUTIL_PC_NO_FLOOD;
+        pm.config |= OFPUTIL_PC_NO_FLOOD;
     } else if (!strcasecmp(argv[3], "forward")) {
-        opm->mask |= htonl(OFPPC_NO_FWD);
+        pm.mask |= OFPUTIL_PC_NO_FWD;
     } else if (!strcasecmp(argv[3], "noforward")) {
-        opm->mask |= htonl(OFPPC_NO_FWD);
-        opm->config |= htonl(OFPPC_NO_FWD);
+        pm.mask |= OFPUTIL_PC_NO_FWD;
+        pm.config |= OFPUTIL_PC_NO_FWD;
     } else {
         ovs_fatal(0, "unknown mod-port command '%s'", argv[3]);
     }
 
-    open_vconn(argv[1], &vconn);
-    transact_noreply(vconn, request);
+    protocol = open_vconn(argv[1], &vconn);
+    transact_noreply(vconn, ofputil_encode_port_mod(&pm, protocol));
     vconn_close(vconn);
 }