From 9e1fd49b0cf494315c82f27c651486ef82e83446 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 15 Feb 2012 16:33:04 -0800 Subject: [PATCH] Abstract everything that uses ofp_phy_port, add OF1.1 support. Reviewed-by: Simon Horman Signed-off-by: Ben Pfaff --- include/openflow/openflow-1.0.h | 159 +++------ include/openflow/openflow-1.1.h | 76 ++++ include/openflow/openflow-common.h | 90 +++++ lib/learning-switch.c | 33 +- lib/ofp-errors.h | 3 + lib/ofp-print.c | 333 +++++++++++++----- lib/ofp-util.c | 537 ++++++++++++++++++++++++++++- lib/ofp-util.h | 143 +++++++- ofproto/connmgr.c | 16 +- ofproto/connmgr.h | 5 +- ofproto/ofproto-dpif.c | 74 ++-- ofproto/ofproto-provider.h | 30 +- ofproto/ofproto.c | 172 ++++----- tests/ofp-print.at | 116 ++++++- tests/ofproto.at | 18 +- utilities/ovs-ofctl.c | 76 ++-- 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); } -- 2.30.2