* 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);
{
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 size_t
+ofputil_get_phy_port_size(uint8_t ofp_version)
+{
+ return ofp_version == OFP10_VERSION ? sizeof(struct ofp10_phy_port)
+ : sizeof(struct ofp11_port);
+}
+
static void
ofputil_encode_ofp10_phy_port(const struct ofputil_phy_port *pp,
struct ofp10_phy_port *opp)
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;
}
+/* Returns true if the maximum number of ports are in 'osf'. */
+static bool
+max_ports_in_features(const struct ofp_switch_features *osf)
+{
+ size_t pp_size = ofputil_get_phy_port_size(osf->header.version);
+ return ntohs(osf->header.length) + pp_size > UINT16_MAX;
+}
+
+/* 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)
+{
+ 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
encode_action_bits(enum ofputil_action_bitmap ofputil_actions,
const struct ofputil_action_bit_translation *x)
case OFPP_FLOOD:
case OFPP_ALL:
case OFPP_CONTROLLER:
+ case OFPP_NONE:
case OFPP_LOCAL:
return 0;
* 'ofp_version', returns the number of elements. */
size_t ofputil_count_phy_ports(uint8_t ofp_version, struct ofpbuf *b)
{
- return (ofp_version == OFP10_VERSION
- ? b->size / sizeof(struct ofp10_phy_port)
- : b->size / sizeof(struct ofp11_port));
+ return b->size / ofputil_get_phy_port_size(ofp_version);
}
static enum ofperr
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;
}