* name. */
#define WC_INVARIANT_LIST \
WC_INVARIANT_BIT(IN_PORT) \
- WC_INVARIANT_BIT(DL_SRC) \
- WC_INVARIANT_BIT(DL_DST) \
WC_INVARIANT_BIT(DL_TYPE) \
WC_INVARIANT_BIT(NW_PROTO)
void
ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
/* Initialize most of rule->wc. */
flow_wildcards_init_catchall(wc);
wc->tp_dst_mask = htons(UINT16_MAX);
}
- if (ofpfw & OFPFW_DL_DST) {
- /* OpenFlow 1.0 OFPFW_DL_DST covers the whole Ethernet destination, but
- * Open vSwitch breaks the Ethernet destination into bits as FWW_DL_DST
- * and FWW_ETH_MCAST. */
- wc->wildcards |= FWW_ETH_MCAST;
+ if (!(ofpfw & OFPFW_DL_SRC)) {
+ memset(wc->dl_src_mask, 0xff, ETH_ADDR_LEN);
+ }
+ if (!(ofpfw & OFPFW_DL_DST)) {
+ memset(wc->dl_dst_mask, 0xff, ETH_ADDR_LEN);
}
/* VLAN TCI mask. */
if (!wc->tp_dst_mask) {
ofpfw |= OFPFW_TP_DST;
}
+ if (eth_addr_is_zero(wc->dl_src_mask)) {
+ ofpfw |= OFPFW_DL_SRC;
+ }
+ if (eth_addr_is_zero(wc->dl_dst_mask)) {
+ ofpfw |= OFPFW_DL_DST;
+ }
/* Translate VLANs. */
match->dl_vlan = htons(0);
OFPST_QUEUE, "OFPST_QUEUE request",
sizeof(struct ofp_queue_stats_request), 0 },
+ { OFPUTIL_OFPST_PORT_DESC_REQUEST, OFP10_VERSION,
+ OFPST_PORT_DESC, "OFPST_PORT_DESC request",
+ sizeof(struct ofp_stats_msg), 0 },
+
{ 0, 0,
OFPST_VENDOR, "OFPST_VENDOR request",
sizeof(struct ofp_vendor_stats_msg), 1 },
OFPST_QUEUE, "OFPST_QUEUE reply",
sizeof(struct ofp_stats_msg), sizeof(struct ofp_queue_stats) },
+ { OFPUTIL_OFPST_PORT_DESC_REPLY, OFP10_VERSION,
+ OFPST_PORT_DESC, "OFPST_PORT_DESC reply",
+ sizeof(struct ofp_stats_msg), sizeof(struct ofp10_phy_port) },
+
{ 0, 0,
OFPST_VENDOR, "OFPST_VENDOR reply",
sizeof(struct ofp_vendor_stats_msg), 1 },
{
const struct flow_wildcards *wc = &rule->wc;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
- /* Only NXM supports separately wildcards the Ethernet multicast bit. */
- if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) {
+ /* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */
+ if (!eth_mask_is_exact(wc->dl_src_mask)
+ && !eth_addr_is_zero(wc->dl_src_mask)) {
+ return OFPUTIL_P_NXM_ANY;
+ }
+ if (!eth_mask_is_exact(wc->dl_dst_mask)
+ && !eth_addr_is_zero(wc->dl_dst_mask)) {
return OFPUTIL_P_NXM_ANY;
}
ofputil_normalize_rule(&fm->cr);
/* Translate the message. */
- fm->cookie = ofm->cookie;
- fm->cookie_mask = htonll(UINT64_MAX);
command = ntohs(ofm->command);
+ fm->cookie = htonll(0);
+ fm->cookie_mask = htonll(0);
+ fm->new_cookie = ofm->cookie;
fm->idle_timeout = ntohs(ofm->idle_timeout);
fm->hard_timeout = ntohs(ofm->hard_timeout);
fm->buffer_id = ntohl(ofm->buffer_id);
/* Translate the message. */
command = ntohs(nfm->command);
- if (command == OFPFC_ADD) {
- if (fm->cookie_mask) {
- /* The "NXM_NX_COOKIE*" matches are not valid for flow
- * additions. Additions must use the "cookie" field of
- * the "nx_flow_mod" structure. */
- return OFPERR_NXBRC_NXM_INVALID;
- } else {
- fm->cookie = nfm->cookie;
- fm->cookie_mask = htonll(UINT64_MAX);
- }
+ if ((command & 0xff) == OFPFC_ADD && fm->cookie_mask) {
+ /* Flow additions may only set a new cookie, not match an
+ * existing cookie. */
+ return OFPERR_NXBRC_NXM_INVALID;
}
+ fm->new_cookie = nfm->cookie;
fm->idle_timeout = ntohs(nfm->idle_timeout);
fm->hard_timeout = ntohs(nfm->hard_timeout);
fm->buffer_id = ntohl(nfm->buffer_id);
}
/* Converts 'fm' into an OFPT_FLOW_MOD or NXT_FLOW_MOD message according to
- * 'protocol' and returns the message.
- *
- * 'flow_mod_table_id' should be true if the NXT_FLOW_MOD_TABLE_ID extension is
- * enabled, false otherwise. */
+ * 'protocol' and returns the message. */
struct ofpbuf *
ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
enum ofputil_protocol protocol)
msg = ofpbuf_new(sizeof *ofm + actions_len);
ofm = put_openflow(sizeof *ofm, OFPT10_FLOW_MOD, msg);
ofputil_cls_rule_to_match(&fm->cr, &ofm->match);
- ofm->cookie = fm->cookie;
+ ofm->cookie = fm->new_cookie;
ofm->command = htons(command);
ofm->idle_timeout = htons(fm->idle_timeout);
ofm->hard_timeout = htons(fm->hard_timeout);
put_nxmsg(sizeof *nfm, NXT_FLOW_MOD, msg);
nfm = msg->data;
nfm->command = htons(command);
- if (command == OFPFC_ADD) {
- nfm->cookie = fm->cookie;
- match_len = nx_put_match(msg, &fm->cr, 0, 0);
- } else {
- nfm->cookie = 0;
- match_len = nx_put_match(msg, &fm->cr,
- fm->cookie, fm->cookie_mask);
- }
+ nfm->cookie = fm->new_cookie;
+ match_len = nx_put_match(msg, false, &fm->cr,
+ fm->cookie, fm->cookie_mask);
nfm->idle_timeout = htons(fm->idle_timeout);
nfm->hard_timeout = htons(fm->hard_timeout);
nfm->priority = htons(fm->cr.priority);
if (fm->table_id != 0xff) {
usable_protocols &= OFPUTIL_P_TID;
}
- if (fm->command != OFPFC_ADD && fm->cookie_mask != htonll(0)) {
+
+ /* Matching of the cookie is only supported through NXM. */
+ if (fm->cookie_mask != htonll(0)) {
usable_protocols &= OFPUTIL_P_NXM_ANY;
}
}
subtype = fsr->aggregate ? NXST_AGGREGATE : NXST_FLOW;
ofputil_make_stats_request(sizeof *nfsr, OFPST_VENDOR, subtype, &msg);
- match_len = nx_put_match(msg, &fsr->match,
+ match_len = nx_put_match(msg, false, &fsr->match,
fsr->cookie, fsr->cookie_mask);
nfsr = msg->data;
nfs->hard_age = htons(fs->hard_age < 0 ? 0
: fs->hard_age < UINT16_MAX ? fs->hard_age + 1
: UINT16_MAX);
- nfs->match_len = htons(nx_put_match(msg, &fs->rule, 0, 0));
+ nfs->match_len = htons(nx_put_match(msg, false, &fs->rule, 0, 0));
nfs->cookie = fs->cookie;
nfs->packet_count = htonll(fs->packet_count);
nfs->byte_count = htonll(fs->byte_count);
int match_len;
make_nxmsg_xid(sizeof *nfr, NXT_FLOW_REMOVED, htonl(0), &msg);
- match_len = nx_put_match(msg, &fr->rule, 0, 0);
+ match_len = nx_put_match(msg, false, &fr->rule, 0, 0);
nfr = msg->data;
nfr->cookie = fr->cookie;
npi = ofpbuf_pull(&b, sizeof *npi);
error = nx_pull_match_loose(&b, ntohs(npi->match_len), 0, &rule, NULL,
- NULL);
+ NULL);
if (error) {
return error;
}
cls_rule_set_in_port(&rule, pin->fmd.in_port);
ofpbuf_put_zeros(packet, sizeof *npi);
- match_len = nx_put_match(packet, &rule, 0, 0);
+ match_len = nx_put_match(packet, false, &rule, 0, 0);
ofpbuf_put_zeros(packet, 2);
ofpbuf_put(packet, pin->packet, send_len);
return 0;
}
-static int
-ofputil_pull_phy_port(uint8_t ofp_version, struct ofpbuf *b,
- struct ofputil_phy_port *pp)
+static size_t
+ofputil_get_phy_port_size(uint8_t ofp_version)
{
- 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;
- }
+ return ofp_version == OFP10_VERSION ? sizeof(struct ofp10_phy_port)
+ : sizeof(struct ofp11_port);
}
static void
}
}
}
+
+void
+ofputil_append_port_desc_stats_reply(uint8_t ofp_version,
+ const struct ofputil_phy_port *pp,
+ struct list *replies)
+{
+ if (ofp_version == OFP10_VERSION) {
+ struct ofp10_phy_port *opp;
+
+ opp = ofputil_append_stats_reply(sizeof *opp, replies);
+ ofputil_encode_ofp10_phy_port(pp, opp);
+ } else {
+ struct ofp11_port *op;
+
+ op = ofputil_append_stats_reply(sizeof *op, replies);
+ ofputil_encode_ofp11_port(pp, op);
+ }
+}
\f
/* ofputil_switch_features */
/* 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
+ * ofputil_pull_phy_port(). Returns 0 if successful, otherwise an
* OFPERR_* value. */
enum ofperr
ofputil_decode_switch_features(const struct ofp_switch_features *osf,
{
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 (b->size % ofputil_get_phy_port_size(osf->header.version)) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ if (osf->header.version == OFP10_VERSION) {
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;
}
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)
+/* Returns true if the maximum number of ports are in 'osf'. */
+static bool
+max_ports_in_features(const struct ofp_switch_features *osf)
{
- const struct ofp_switch_features *osf = b->l2;
- return ofputil_pull_phy_port(osf->header.version, b, pp);
+ size_t pp_size = ofputil_get_phy_port_size(osf->header.version);
+ return ntohs(osf->header.length) + pp_size > UINT16_MAX;
}
-/* 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)
+/* Given a buffer 'b' that contains a Features Reply message, checks if
+ * it contains the maximum number of ports that will fit. If so, it
+ * returns true and removes the ports from the message. The caller
+ * should then send an OFPST_PORT_DESC stats request to get the ports,
+ * since the switch may have more ports than could be represented in the
+ * Features Reply. Otherwise, returns false.
+ */
+bool
+ofputil_switch_features_ports_trunc(struct ofpbuf *b)
{
- 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));
+ struct ofp_switch_features *osf = b->data;
+
+ if (max_ports_in_features(osf)) {
+ /* Remove all the ports. */
+ b->size = sizeof(*osf);
+ update_openflow_length(b);
+
+ return true;
+ }
+
+ return false;
}
static ovs_be32
case OFPP_FLOOD:
case OFPP_ALL:
case OFPP_CONTROLLER:
+ case OFPP_NONE:
case OFPP_LOCAL:
return 0;
ds_put_cstr(s, name);
}
+/* Given a buffer 'b' that contains an array of OpenFlow ports of type
+ * 'ofp_version', tries to pull the first element from the array. If
+ * successful, initializes '*pp' with an abstract representation of the
+ * port and returns 0. If no ports remain to be decoded, returns EOF.
+ * On an error, returns a positive OFPERR_* value. */
+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;
+ }
+}
+
+/* Given a buffer 'b' that contains an array of OpenFlow ports of type
+ * 'ofp_version', returns the number of elements. */
+size_t ofputil_count_phy_ports(uint8_t ofp_version, struct ofpbuf *b)
+{
+ return b->size / ofputil_get_phy_port_size(ofp_version);
+}
+
static enum ofperr
check_resubmit_table(const struct nx_action_resubmit *nar)
{
bool
action_outputs_to_port(const union ofp_action *action, ovs_be16 port)
{
- switch (ntohs(action->type)) {
- case OFPAT10_OUTPUT:
+ switch (ofputil_decode_action(action)) {
+ case OFPUTIL_OFPAT10_OUTPUT:
return action->output.port == port;
- case OFPAT10_ENQUEUE:
+ case OFPUTIL_OFPAT10_ENQUEUE:
return ((const struct ofp_action_enqueue *) action)->port == port;
+ case OFPUTIL_NXAST_CONTROLLER:
+ return port == htons(OFPP_CONTROLLER);
default:
return false;
}