aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/openflow/openflow-1.0.h159
-rw-r--r--include/openflow/openflow-1.1.h76
-rw-r--r--include/openflow/openflow-common.h90
-rw-r--r--lib/learning-switch.c33
-rw-r--r--lib/ofp-errors.h3
-rw-r--r--lib/ofp-print.c333
-rw-r--r--lib/ofp-util.c537
-rw-r--r--lib/ofp-util.h143
-rw-r--r--ofproto/connmgr.c16
-rw-r--r--ofproto/connmgr.h5
-rw-r--r--ofproto/ofproto-dpif.c74
-rw-r--r--ofproto/ofproto-provider.h30
-rw-r--r--ofproto/ofproto.c172
-rw-r--r--tests/ofp-print.at116
-rw-r--r--tests/ofproto.at18
-rw-r--r--utilities/ovs-ofctl.c76
16 files changed, 1449 insertions, 432 deletions
diff --git a/include/openflow/openflow-1.0.h b/include/openflow/openflow-1.0.h
index bca1067b..5844a96c 100644
--- a/include/openflow/openflow-1.0.h
+++ b/include/openflow/openflow-1.0.h
@@ -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 {
diff --git a/include/openflow/openflow-1.1.h b/include/openflow/openflow-1.1.h
index 0e5c901a..d02ece39 100644
--- a/include/openflow/openflow-1.1.h
+++ b/include/openflow/openflow-1.1.h
@@ -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. */
diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h
index d0f4b181..89c191b5 100644
--- a/include/openflow/openflow-common.h
+++ b/include/openflow/openflow-common.h
@@ -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 */
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index fb529f5c..9e36db88 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -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
diff --git a/lib/ofp-errors.h b/lib/ofp-errors.h
index 28fa1122..cef32f29 100644
--- a/lib/ofp-errors.h
+++ b/lib/ofp-errors.h
@@ -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 ## */
/* ## ---------------- ## */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 1d71fc9e..79e23a93 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -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
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index e29450f8..3099b0b3 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -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);
+ }
+ }
+}
+
+/* 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);
+}
+
+/* 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;
+}
+
+/* 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)
{
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 5004758a..2172fd6b 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -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 **);
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index ae0d3db6..55b0306f 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -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);
}
}
}
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index 14698aba..2869ba78 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -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 *,
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index fe10f120..457bbb78 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -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;
}
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 9ba62de1..04c156a0 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -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.
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index f9ed23ef..d03bd9b3 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -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));
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 46b16175..9ac1d23f 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -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
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 0bc997cf..b39de70d 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -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
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index d81e2957..fcbbf215 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -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);
}