struct hmap_node hmap_node;
enum nxm_field_index index; /* NFI_* value. */
uint32_t header; /* NXM_* value. */
- uint32_t wildcard; /* Wildcard bit, if exactly one. */
+ flow_wildcards_t wildcard; /* FWW_* bit, if exactly one. */
ovs_be16 dl_type; /* dl_type prerequisite, if nonzero. */
uint8_t nw_proto; /* nw_proto prerequisite, if nonzero. */
const char *name; /* "NXM_*" string. */
\f
/* nx_pull_match() and helpers. */
-static int
-parse_tci(struct cls_rule *rule, ovs_be16 tci, ovs_be16 mask)
-{
- enum { OFPFW_DL_TCI = OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP };
- if ((rule->wc.wildcards & OFPFW_DL_TCI) != OFPFW_DL_TCI) {
- return NXM_DUP_TYPE;
- } else {
- return cls_rule_set_dl_tci_masked(rule, tci, mask) ? 0 : NXM_INVALID;
- }
-}
-
static int
parse_nx_reg(const struct nxm_field *f,
struct flow *flow, struct flow_wildcards *wc,
} else {
flow_wildcards_set_reg_mask(wc, idx,
(NXM_HASMASK(f->header)
- ? ntohl(get_unaligned_u32(maskp))
+ ? ntohl(get_unaligned_be32(maskp))
: UINT32_MAX));
- flow->regs[idx] = ntohl(get_unaligned_u32(value));
+ flow->regs[idx] = ntohl(get_unaligned_be32(value));
flow->regs[idx] &= wc->reg_masks[idx];
return 0;
}
switch (f->index) {
/* Metadata. */
case NFI_NXM_OF_IN_PORT:
- flow->in_port = ntohs(get_unaligned_u16(value));
+ flow->in_port = ntohs(get_unaligned_be16(value));
if (flow->in_port == OFPP_LOCAL) {
flow->in_port = ODPP_LOCAL;
}
/* Ethernet header. */
case NFI_NXM_OF_ETH_DST:
- if ((wc->wildcards & (OFPFW_DL_DST | FWW_ETH_MCAST))
- != (OFPFW_DL_DST | FWW_ETH_MCAST)) {
+ if ((wc->wildcards & (FWW_DL_DST | FWW_ETH_MCAST))
+ != (FWW_DL_DST | FWW_ETH_MCAST)) {
return NXM_DUP_TYPE;
} else {
- wc->wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
+ wc->wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
return 0;
}
case NFI_NXM_OF_ETH_DST_W:
- if ((wc->wildcards & (OFPFW_DL_DST | FWW_ETH_MCAST))
- != (OFPFW_DL_DST | FWW_ETH_MCAST)) {
+ if ((wc->wildcards & (FWW_DL_DST | FWW_ETH_MCAST))
+ != (FWW_DL_DST | FWW_ETH_MCAST)) {
return NXM_DUP_TYPE;
} else if (eth_addr_equals(mask, eth_mcast_1)) {
wc->wildcards &= ~FWW_ETH_MCAST;
flow->dl_dst[0] = *(uint8_t *) value & 0x01;
} else if (eth_addr_equals(mask, eth_mcast_0)) {
- wc->wildcards &= ~OFPFW_DL_DST;
+ wc->wildcards &= ~FWW_DL_DST;
memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
flow->dl_dst[0] &= 0xfe;
} else if (eth_addr_equals(mask, eth_all_0s)) {
return 0;
} else if (eth_addr_equals(mask, eth_all_1s)) {
- wc->wildcards &= ~(OFPFW_DL_DST | FWW_ETH_MCAST);
+ wc->wildcards &= ~(FWW_DL_DST | FWW_ETH_MCAST);
memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
return 0;
} else {
memcpy(flow->dl_src, value, ETH_ADDR_LEN);
return 0;
case NFI_NXM_OF_ETH_TYPE:
- flow->dl_type = get_unaligned_u16(value);
+ flow->dl_type = get_unaligned_be16(value);
return 0;
/* 802.1Q header. */
case NFI_NXM_OF_VLAN_TCI:
- return parse_tci(rule, get_unaligned_u16(value), htons(UINT16_MAX));
-
+ if (wc->vlan_tci_mask) {
+ return NXM_DUP_TYPE;
+ } else {
+ cls_rule_set_dl_tci(rule, get_unaligned_be16(value));
+ return 0;
+ }
case NFI_NXM_OF_VLAN_TCI_W:
- return parse_tci(rule, get_unaligned_u16(value),
- get_unaligned_u16(mask));
+ if (wc->vlan_tci_mask) {
+ return NXM_DUP_TYPE;
+ } else {
+ cls_rule_set_dl_tci_masked(rule, get_unaligned_be16(value),
+ get_unaligned_be16(mask));
+ return 0;
+ }
/* IP header. */
case NFI_NXM_OF_IP_TOS:
if (wc->nw_src_mask) {
return NXM_DUP_TYPE;
} else {
- cls_rule_set_nw_src(rule, get_unaligned_u32(value));
+ cls_rule_set_nw_src(rule, get_unaligned_be32(value));
return 0;
}
case NFI_NXM_OF_IP_SRC_W:
if (wc->nw_src_mask) {
return NXM_DUP_TYPE;
} else {
- ovs_be32 ip = get_unaligned_u32(value);
- ovs_be32 netmask = get_unaligned_u32(mask);
+ ovs_be32 ip = get_unaligned_be32(value);
+ ovs_be32 netmask = get_unaligned_be32(mask);
if (!cls_rule_set_nw_src_masked(rule, ip, netmask)) {
return NXM_BAD_MASK;
}
if (wc->nw_dst_mask) {
return NXM_DUP_TYPE;
} else {
- cls_rule_set_nw_dst(rule, get_unaligned_u32(value));
+ cls_rule_set_nw_dst(rule, get_unaligned_be32(value));
return 0;
}
case NFI_NXM_OF_IP_DST_W:
if (wc->nw_dst_mask) {
return NXM_DUP_TYPE;
} else {
- ovs_be32 ip = get_unaligned_u32(value);
- ovs_be32 netmask = get_unaligned_u32(mask);
+ ovs_be32 ip = get_unaligned_be32(value);
+ ovs_be32 netmask = get_unaligned_be32(mask);
if (!cls_rule_set_nw_dst_masked(rule, ip, netmask)) {
return NXM_BAD_MASK;
}
/* TCP header. */
case NFI_NXM_OF_TCP_SRC:
- flow->tp_src = get_unaligned_u16(value);
+ flow->tp_src = get_unaligned_be16(value);
return 0;
case NFI_NXM_OF_TCP_DST:
- flow->tp_dst = get_unaligned_u16(value);
+ flow->tp_dst = get_unaligned_be16(value);
return 0;
/* UDP header. */
case NFI_NXM_OF_UDP_SRC:
- flow->tp_src = get_unaligned_u16(value);
+ flow->tp_src = get_unaligned_be16(value);
return 0;
case NFI_NXM_OF_UDP_DST:
- flow->tp_dst = get_unaligned_u16(value);
+ flow->tp_dst = get_unaligned_be16(value);
return 0;
/* ICMP header. */
/* ARP header. */
case NFI_NXM_OF_ARP_OP:
- if (ntohs(get_unaligned_u16(value)) > 255) {
+ if (ntohs(get_unaligned_be16(value)) > 255) {
return NXM_BAD_VALUE;
} else {
- flow->nw_proto = ntohs(get_unaligned_u16(value));
+ flow->nw_proto = ntohs(get_unaligned_be16(value));
return 0;
}
/* Tunnel ID. */
case NFI_NXM_NX_TUN_ID:
- flow->tun_id = htonl(ntohll(get_unaligned_u64(value)));
+ flow->tun_id = htonl(ntohll(get_unaligned_be64(value)));
return 0;
/* Registers. */
ofpbuf_put(b, &mask, sizeof mask);
}
+static void
+nxm_put_16m(struct ofpbuf *b, uint32_t header, ovs_be16 value, ovs_be16 mask)
+{
+ switch (mask) {
+ case 0:
+ break;
+
+ case CONSTANT_HTONS(UINT16_MAX):
+ nxm_put_16(b, header, value);
+ break;
+
+ default:
+ nxm_put_16w(b, NXM_MAKE_WILD_HEADER(header), value, mask);
+ break;
+ }
+}
+
static void
nxm_put_32(struct ofpbuf *b, uint32_t header, ovs_be32 value)
{
case 0:
break;
- case UINT32_MAX:
+ case CONSTANT_HTONL(UINT32_MAX):
nxm_put_32(b, header, value);
break;
nxm_put_eth_dst(struct ofpbuf *b,
uint32_t wc, const uint8_t value[ETH_ADDR_LEN])
{
- switch (wc & (OFPFW_DL_DST | FWW_ETH_MCAST)) {
- case OFPFW_DL_DST | FWW_ETH_MCAST:
+ switch (wc & (FWW_DL_DST | FWW_ETH_MCAST)) {
+ case FWW_DL_DST | FWW_ETH_MCAST:
break;
- case OFPFW_DL_DST:
+ case FWW_DL_DST:
nxm_put_header(b, NXM_OF_ETH_DST_W);
ofpbuf_put(b, value, ETH_ADDR_LEN);
ofpbuf_put(b, eth_mcast_1, ETH_ADDR_LEN);
int
nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
{
- const uint32_t wc = cr->wc.wildcards;
+ const flow_wildcards_t wc = cr->wc.wildcards;
const struct flow *flow = &cr->flow;
const size_t start_len = b->size;
- ovs_be16 vid, pcp;
int match_len;
int i;
/* Metadata. */
- if (!(wc & OFPFW_IN_PORT)) {
+ if (!(wc & FWW_IN_PORT)) {
uint16_t in_port = flow->in_port;
if (in_port == ODPP_LOCAL) {
in_port = OFPP_LOCAL;
/* Ethernet. */
nxm_put_eth_dst(b, wc, flow->dl_dst);
- if (!(wc & OFPFW_DL_SRC)) {
+ if (!(wc & FWW_DL_SRC)) {
nxm_put_eth(b, NXM_OF_ETH_SRC, flow->dl_src);
}
- if (!(wc & OFPFW_DL_TYPE)) {
+ if (!(wc & FWW_DL_TYPE)) {
nxm_put_16(b, NXM_OF_ETH_TYPE, flow->dl_type);
}
/* 802.1Q. */
- vid = flow->dl_vlan & htons(VLAN_VID_MASK);
- pcp = htons((flow->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK);
- switch (wc & (OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP)) {
- case OFPFW_DL_VLAN | OFPFW_DL_VLAN_PCP:
- break;
- case OFPFW_DL_VLAN:
- nxm_put_16w(b, NXM_OF_VLAN_TCI_W, pcp | htons(VLAN_CFI),
- htons(VLAN_PCP_MASK | VLAN_CFI));
- break;
- case OFPFW_DL_VLAN_PCP:
- if (flow->dl_vlan == htons(OFP_VLAN_NONE)) {
- nxm_put_16(b, NXM_OF_VLAN_TCI, 0);
- } else {
- nxm_put_16w(b, NXM_OF_VLAN_TCI_W, vid | htons(VLAN_CFI),
- htons(VLAN_VID_MASK | VLAN_CFI));
- }
- break;
- case 0:
- if (flow->dl_vlan == htons(OFP_VLAN_NONE)) {
- nxm_put_16(b, NXM_OF_VLAN_TCI, 0);
- } else {
- nxm_put_16(b, NXM_OF_VLAN_TCI, vid | pcp | htons(VLAN_CFI));
- }
- break;
- }
+ nxm_put_16m(b, NXM_OF_VLAN_TCI, flow->vlan_tci, cr->wc.vlan_tci_mask);
- if (!(wc & OFPFW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_IP)) {
+ /* L3. */
+ if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_IP)) {
/* IP. */
- if (!(wc & OFPFW_NW_TOS)) {
+ if (!(wc & FWW_NW_TOS)) {
nxm_put_8(b, NXM_OF_IP_TOS, flow->nw_tos & 0xfc);
}
nxm_put_32m(b, NXM_OF_IP_SRC, flow->nw_src, cr->wc.nw_src_mask);
nxm_put_32m(b, NXM_OF_IP_DST, flow->nw_dst, cr->wc.nw_dst_mask);
- if (!(wc & OFPFW_NW_PROTO)) {
+ if (!(wc & FWW_NW_PROTO)) {
nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto);
switch (flow->nw_proto) {
/* TCP. */
case IP_TYPE_TCP:
- if (!(wc & OFPFW_TP_SRC)) {
+ if (!(wc & FWW_TP_SRC)) {
nxm_put_16(b, NXM_OF_TCP_SRC, flow->tp_src);
}
- if (!(wc & OFPFW_TP_DST)) {
+ if (!(wc & FWW_TP_DST)) {
nxm_put_16(b, NXM_OF_TCP_DST, flow->tp_dst);
}
break;
/* UDP. */
case IP_TYPE_UDP:
- if (!(wc & OFPFW_TP_SRC)) {
+ if (!(wc & FWW_TP_SRC)) {
nxm_put_16(b, NXM_OF_UDP_SRC, flow->tp_src);
}
- if (!(wc & OFPFW_TP_DST)) {
+ if (!(wc & FWW_TP_DST)) {
nxm_put_16(b, NXM_OF_UDP_DST, flow->tp_dst);
}
break;
/* ICMP. */
case IP_TYPE_ICMP:
- if (!(wc & OFPFW_TP_SRC)) {
+ if (!(wc & FWW_TP_SRC)) {
nxm_put_8(b, NXM_OF_ICMP_TYPE, ntohs(flow->tp_src));
}
- if (!(wc & OFPFW_TP_DST)) {
+ if (!(wc & FWW_TP_DST)) {
nxm_put_8(b, NXM_OF_ICMP_CODE, ntohs(flow->tp_dst));
}
break;
}
}
- } else if (!(wc & OFPFW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_ARP)) {
+ } else if (!(wc & FWW_DL_TYPE) && flow->dl_type == htons(ETH_TYPE_ARP)) {
/* ARP. */
- if (!(wc & OFPFW_NW_PROTO)) {
+ if (!(wc & FWW_NW_PROTO)) {
nxm_put_16(b, NXM_OF_ARP_OP, htons(flow->nw_proto));
}
nxm_put_32m(b, NXM_OF_ARP_SPA, flow->nw_src, cr->wc.nw_src_mask);
}
/* Tunnel ID. */
- if (!(wc & NXFW_TUN_ID)) {
+ if (!(wc & FWW_TUN_ID)) {
nxm_put_64(b, NXM_NX_TUN_ID, htonll(ntohl(flow->tun_id)));
}
return ds_steal_cstr(&s);
}
-static const struct nxm_field *
-lookup_nxm_field(const char *name, int name_len)
+static uint32_t
+parse_nxm_field_name(const char *name, int name_len)
{
const struct nxm_field *f;
+ /* Check whether it's a field name. */
for (f = nxm_fields; f < &nxm_fields[ARRAY_SIZE(nxm_fields)]; f++) {
if (!strncmp(f->name, name, name_len) && f->name[name_len] == '\0') {
- return f;
+ return f->header;
}
}
- return NULL;
+ /* Check whether it's a 32-bit field header value as hex.
+ * (This isn't ordinarily useful except for testing error behavior.) */
+ if (name_len == 8) {
+ uint32_t header = hexits_value(name, name_len, NULL);
+ if (header != UINT_MAX) {
+ return header;
+ }
+ }
+
+ return 0;
}
static const char *
parse_hex_bytes(struct ofpbuf *b, const char *s, unsigned int n)
{
while (n--) {
- int low, high;
uint8_t byte;
+ bool ok;
s += strspn(s, " ");
- low = hexit_value(*s);
- high = low < 0 ? low : hexit_value(s[1]);
- if (low < 0 || high < 0) {
+ byte = hexits_value(s, 2, &ok);
+ if (!ok) {
ovs_fatal(0, "%.2s: hex digits expected", s);
}
- byte = 16 * low + high;
ofpbuf_put(b, &byte, 1);
s += 2;
}
}
for (s += strspn(s, ", "); *s; s += strspn(s, ", ")) {
- const struct nxm_field *f;
+ const char *name;
+ uint32_t header;
int name_len;
+ name = s;
name_len = strcspn(s, "(");
if (s[name_len] != '(') {
ovs_fatal(0, "%s: missing ( at end of nx_match", full_s);
}
- f = lookup_nxm_field(s, name_len);
- if (!f) {
+ header = parse_nxm_field_name(name, name_len);
+ if (!header) {
ovs_fatal(0, "%s: unknown field `%.*s'", full_s, name_len, s);
}
s += name_len + 1;
- nxm_put_header(b, f->header);
- s = parse_hex_bytes(b, s, nxm_field_bytes(f->header));
- if (NXM_HASMASK(f->header)) {
+ nxm_put_header(b, header);
+ s = parse_hex_bytes(b, s, nxm_field_bytes(header));
+ if (NXM_HASMASK(header)) {
s += strspn(s, " ");
if (*s != '/') {
- ovs_fatal(0, "%s: missing / in masked field %s",
- full_s, f->name);
+ ovs_fatal(0, "%s: missing / in masked field %.*s",
+ full_s, name_len, name);
}
- s = parse_hex_bytes(b, s + 1, nxm_field_bytes(f->header));
+ s = parse_hex_bytes(b, s + 1, nxm_field_bytes(header));
}
s += strspn(s, " ");
if (*s != ')') {
- ovs_fatal(0, "%s: missing ) following field %s", full_s, f->name);
+ ovs_fatal(0, "%s: missing ) following field %.*s",
+ full_s, name_len, name);
}
s++;
}
return ntohs(flow->dl_type);
case NFI_NXM_OF_VLAN_TCI:
- if (flow->dl_vlan == htons(OFP_VLAN_NONE)) {
- return 0;
- } else {
- return (ntohs(flow->dl_vlan & htons(VLAN_VID_MASK))
- | ((flow->dl_vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK)
- | VLAN_CFI);
- }
+ return ntohs(flow->vlan_tci);
case NFI_NXM_OF_IP_TOS:
return flow->nw_tos;
if (NXM_IS_NX_REG(dst->header)) {
flow->regs[NXM_NX_REG_IDX(dst->header)] = new_data;
} else if (dst->header == NXM_OF_VLAN_TCI) {
- ovs_be16 vlan_tci = htons(new_data & VLAN_CFI ? new_data : 0);
- flow->dl_vlan = htons(vlan_tci_to_vid(vlan_tci));
- flow->dl_vlan_pcp = vlan_tci_to_pcp(vlan_tci);
+ flow->vlan_tci = htons(new_data);
} else if (dst->header == NXM_NX_TUN_ID) {
flow->tun_id = htonl(new_data);
} else {