NXM_OF_VLAN_TCI, "NXM_OF_VLAN_TCI",
NXM_OF_VLAN_TCI, "NXM_OF_VLAN_TCI",
}, {
- MFF_VLAN_VID, "dl_vlan", NULL,
+ MFF_DL_VLAN, "dl_vlan", NULL,
sizeof(ovs_be16), 12,
MFM_NONE, 0,
MFS_DECIMAL,
MFP_NONE,
true,
+ 0, NULL,
+ 0, NULL,
+ }, {
+ MFF_VLAN_VID, "vlan_vid", NULL,
+ sizeof(ovs_be16), 12,
+ MFM_FULLY, 0,
+ MFS_DECIMAL,
+ MFP_NONE,
+ true,
OXM_OF_VLAN_VID, "OXM_OF_VLAN_VID",
OXM_OF_VLAN_VID, "OXM_OF_VLAN_VID",
}, {
- MFF_VLAN_PCP, "dl_vlan_pcp", NULL,
+ MFF_DL_VLAN_PCP, "dl_vlan_pcp", NULL,
1, 3,
MFM_NONE, 0,
MFS_DECIMAL,
MFP_NONE,
true,
+ 0, NULL,
+ 0, NULL,
+ }, {
+ MFF_VLAN_PCP, "vlan_pcp", NULL,
+ 1, 3,
+ MFM_NONE, 0,
+ MFS_DECIMAL,
+ MFP_VLAN_VID,
+ true,
OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
},
{
MFF_IPV6_LABEL, "ipv6_label", NULL,
4, 20,
- MFM_NONE, FWW_IPV6_LABEL,
+ MFM_FULLY, 0,
MFS_HEXADECIMAL,
MFP_IPV6,
false,
}, {
MFF_ARP_SHA, "arp_sha", NULL,
MF_FIELD_SIZES(mac),
- MFM_NONE, FWW_ARP_SHA,
+ MFM_FULLY, 0,
MFS_ETHERNET,
MFP_ARP,
false,
}, {
MFF_ARP_THA, "arp_tha", NULL,
MF_FIELD_SIZES(mac),
- MFM_NONE, FWW_ARP_THA,
+ MFM_FULLY, 0,
MFS_ETHERNET,
MFP_ARP,
false,
}, {
MFF_ND_SLL, "nd_sll", NULL,
MF_FIELD_SIZES(mac),
- MFM_NONE, FWW_ARP_SHA,
+ MFM_FULLY, 0,
MFS_ETHERNET,
MFP_ND_SOLICIT,
false,
}, {
MFF_ND_TLL, "nd_tll", NULL,
MF_FIELD_SIZES(mac),
- MFM_NONE, FWW_ARP_THA,
+ MFM_FULLY, 0,
MFS_ETHERNET,
MFP_ND_ADVERT,
false,
case MFF_IP_DSCP:
case MFF_IP_ECN:
case MFF_IP_TTL:
- case MFF_IPV6_LABEL:
case MFF_ARP_OP:
- case MFF_ARP_SHA:
- case MFF_ARP_THA:
- case MFF_ND_SLL:
- case MFF_ND_TLL:
assert(mf->fww_bit != 0);
return (wc->wildcards & mf->fww_bit) != 0;
case MFF_ETH_DST:
return eth_addr_is_zero(wc->dl_dst_mask);
+ case MFF_ARP_SHA:
+ case MFF_ND_SLL:
+ return eth_addr_is_zero(wc->arp_sha_mask);
+
+ case MFF_ARP_THA:
+ case MFF_ND_TLL:
+ return eth_addr_is_zero(wc->arp_tha_mask);
+
case MFF_VLAN_TCI:
return !wc->vlan_tci_mask;
- case MFF_VLAN_VID:
+ case MFF_DL_VLAN:
return !(wc->vlan_tci_mask & htons(VLAN_VID_MASK));
+ case MFF_VLAN_VID:
+ return !(wc->vlan_tci_mask & htons(VLAN_VID_MASK | VLAN_CFI));
+ case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
return !(wc->vlan_tci_mask & htons(VLAN_PCP_MASK));
case MFF_IPV6_DST:
return ipv6_mask_is_any(&wc->ipv6_dst_mask);
+ case MFF_IPV6_LABEL:
+ return !wc->ipv6_label_mask;
+
case MFF_ND_TARGET:
return ipv6_mask_is_any(&wc->nd_target_mask);
case MFF_IP_DSCP:
case MFF_IP_ECN:
case MFF_IP_TTL:
- case MFF_IPV6_LABEL:
case MFF_ARP_OP:
- case MFF_ARP_SHA:
- case MFF_ARP_THA:
- case MFF_ND_SLL:
- case MFF_ND_TLL:
assert(mf->fww_bit != 0);
memset(mask, wc->wildcards & mf->fww_bit ? 0x00 : 0xff, mf->n_bytes);
break;
case MFF_VLAN_TCI:
mask->be16 = wc->vlan_tci_mask;
break;
- case MFF_VLAN_VID:
+ case MFF_DL_VLAN:
mask->be16 = wc->vlan_tci_mask & htons(VLAN_VID_MASK);
break;
+ case MFF_VLAN_VID:
+ mask->be16 = wc->vlan_tci_mask & htons(VLAN_VID_MASK | VLAN_CFI);
+ break;
+ case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
mask->u8 = vlan_tci_to_pcp(wc->vlan_tci_mask);
break;
case MFF_IPV6_DST:
mask->ipv6 = wc->ipv6_dst_mask;
break;
+ case MFF_IPV6_LABEL:
+ mask->be32 = wc->ipv6_label_mask;
+ break;
case MFF_ND_TARGET:
mask->ipv6 = wc->nd_target_mask;
case MFF_ARP_TPA:
mask->be32 = wc->nw_dst_mask;
break;
+ case MFF_ARP_SHA:
+ case MFF_ND_SLL:
+ memcpy(mask->mac, wc->arp_sha_mask, ETH_ADDR_LEN);
+ break;
+ case MFF_ARP_THA:
+ case MFF_ND_TLL:
+ memcpy(mask->mac, wc->arp_tha_mask, ETH_ADDR_LEN);
+ break;
case MFF_TCP_SRC:
case MFF_UDP_SRC:
return flow->dl_type == htons(ETH_TYPE_IP);
case MFP_IPV6:
return flow->dl_type == htons(ETH_TYPE_IPV6);
+ case MFP_VLAN_VID:
+ return (flow->vlan_tci & htons(VLAN_CFI)) != 0;
case MFP_IP_ANY:
return is_ip_any(flow);
case MFF_ARP_OP:
return !(value->be16 & htons(0xff00));
- case MFF_VLAN_VID:
+ case MFF_DL_VLAN:
return !(value->be16 & htons(VLAN_CFI | VLAN_PCP_MASK));
+ case MFF_VLAN_VID:
+ return !(value->be16 & htons(VLAN_PCP_MASK));
+ case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
return !(value->u8 & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT));
value->be16 = flow->vlan_tci;
break;
- case MFF_VLAN_VID:
+ case MFF_DL_VLAN:
value->be16 = flow->vlan_tci & htons(VLAN_VID_MASK);
break;
+ case MFF_VLAN_VID:
+ value->be16 = flow->vlan_tci & htons(VLAN_VID_MASK | VLAN_CFI);
+ break;
+ case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
value->u8 = vlan_tci_to_pcp(flow->vlan_tci);
break;
cls_rule_set_dl_tci(rule, value->be16);
break;
- case MFF_VLAN_VID:
+ case MFF_DL_VLAN:
cls_rule_set_dl_vlan(rule, value->be16);
break;
+ case MFF_VLAN_VID:
+ cls_rule_set_vlan_vid(rule, value->be16);
+ break;
+ case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
cls_rule_set_dl_vlan_pcp(rule, value->u8);
break;
flow->vlan_tci = value->be16;
break;
+ case MFF_DL_VLAN:
+ flow_set_dl_vlan(flow, value->be16);
+ break;
case MFF_VLAN_VID:
flow_set_vlan_vid(flow, value->be16);
break;
+ case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
flow_set_vlan_pcp(flow, value->u8);
break;
cls_rule_set_dl_tci_masked(rule, htons(0), htons(0));
break;
+ case MFF_DL_VLAN:
case MFF_VLAN_VID:
cls_rule_set_any_vid(rule);
break;
+ case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
cls_rule_set_any_pcp(rule);
break;
break;
case MFF_IPV6_LABEL:
- rule->wc.wildcards |= FWW_IPV6_LABEL;
+ rule->wc.ipv6_label_mask = 0;
rule->flow.ipv6_label = 0;
break;
case MFF_ARP_SHA:
case MFF_ND_SLL:
- rule->wc.wildcards |= FWW_ARP_SHA;
- memset(rule->flow.arp_sha, 0, sizeof rule->flow.arp_sha);
+ memset(rule->flow.arp_sha, 0, ETH_ADDR_LEN);
+ memset(rule->wc.arp_sha_mask, 0, ETH_ADDR_LEN);
break;
case MFF_ARP_THA:
case MFF_ND_TLL:
- rule->wc.wildcards |= FWW_ARP_THA;
- memset(rule->flow.arp_tha, 0, sizeof rule->flow.arp_tha);
+ memset(rule->flow.arp_tha, 0, ETH_ADDR_LEN);
+ memset(rule->wc.arp_tha_mask, 0, ETH_ADDR_LEN);
break;
case MFF_TCP_SRC:
switch (mf->id) {
case MFF_IN_PORT:
case MFF_ETH_TYPE:
- case MFF_VLAN_VID:
+ case MFF_DL_VLAN:
+ case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
- case MFF_IPV6_LABEL:
case MFF_IP_PROTO:
case MFF_IP_TTL:
case MFF_IP_DSCP:
case MFF_IP_ECN:
case MFF_ARP_OP:
- case MFF_ARP_SHA:
- case MFF_ARP_THA:
case MFF_ICMPV4_TYPE:
case MFF_ICMPV4_CODE:
case MFF_ICMPV6_TYPE:
case MFF_ICMPV6_CODE:
- case MFF_ND_SLL:
- case MFF_ND_TLL:
NOT_REACHED();
case MFF_TUN_ID:
cls_rule_set_dl_src_masked(rule, value->mac, mask->mac);
break;
+ case MFF_ARP_SHA:
+ case MFF_ND_SLL:
+ cls_rule_set_arp_sha_masked(rule, value->mac, mask->mac);
+ break;
+
+ case MFF_ARP_THA:
+ case MFF_ND_TLL:
+ cls_rule_set_arp_tha_masked(rule, value->mac, mask->mac);
+ break;
+
case MFF_VLAN_TCI:
cls_rule_set_dl_tci_masked(rule, value->be16, mask->be16);
break;
+ case MFF_VLAN_VID:
+ cls_rule_set_vlan_vid_masked(rule, value->be16, mask->be16);
+ break;
+
case MFF_IPV4_SRC:
cls_rule_set_nw_src_masked(rule, value->be32, mask->be32);
break;
cls_rule_set_ipv6_dst_masked(rule, &value->ipv6, &mask->ipv6);
break;
+ case MFF_IPV6_LABEL:
+ if ((mask->be32 & htonl(IPV6_LABEL_MASK)) == htonl(IPV6_LABEL_MASK)) {
+ mf_set_value(mf, value, rule);
+ } else {
+ cls_rule_set_ipv6_label_masked(rule, value->be32, mask->be32);
+ }
+ break;
+
case MFF_ND_TARGET:
cls_rule_set_nd_target_masked(rule, &value->ipv6, &mask->ipv6);
break;
value->be16 &= htons(0xff);
break;
- case MFF_VLAN_VID:
+ case MFF_DL_VLAN:
value->be16 &= htons(VLAN_VID_MASK);
break;
+ case MFF_VLAN_VID:
+ value->be16 &= htons(VLAN_VID_MASK | VLAN_CFI);
+ break;
+ case MFF_DL_VLAN_PCP:
case MFF_VLAN_PCP:
value->u8 &= 0x07;
break;
\f
/* Makes subfield 'sf' within 'rule' exactly match the 'sf->n_bits'
* least-significant bits in 'x'.
- *
- * See mf_set_subfield() for an example.
- *
- * The difference between this function and mf_set_subfield() is that the
- * latter function can only handle subfields up to 64 bits wide, whereas this
- * one handles the general case. On the other hand, mf_set_subfield() is
- * arguably easier to use. */
+ */
void
mf_write_subfield(const struct mf_subfield *sf, const union mf_subvalue *x,
struct cls_rule *rule)
mf_set(field, &value, &mask, rule);
}
-/* Makes subfield 'sf' within 'rule' exactly match the 'sf->n_bits'
- * least-significant bits of 'x'.
- *
- * Example: suppose that 'sf->field' is originally the following 2-byte field
- * in 'rule':
- *
- * value == 0xe00a == 2#1110000000001010
- * mask == 0xfc3f == 2#1111110000111111
- *
- * The call mf_set_subfield(sf, 0x55, 8, 7, rule), where sf->ofs == 8 and
- * sf->n_bits == 7 would have the following effect (note that 0x55 is
- * 2#1010101):
- *
- * value == 0xd50a == 2#1101010100001010
- * mask == 0xff3f == 2#1111111100111111
- * ^^^^^^^ affected bits
- *
- * The caller is responsible for ensuring that the result will be a valid
- * wildcard pattern for 'sf->field'. The caller is responsible for ensuring
- * that 'rule' meets 'sf->field''s prerequisites. */
-void
-mf_set_subfield(const struct mf_subfield *sf, uint64_t x,
- struct cls_rule *rule)
-{
- const struct mf_field *field = sf->field;
- unsigned int n_bits = sf->n_bits;
- unsigned int ofs = sf->ofs;
-
- if (ofs == 0 && field->n_bytes * 8 == n_bits) {
- union mf_value value;
- int i;
-
- for (i = field->n_bytes - 1; i >= 0; i--) {
- ((uint8_t *) &value)[i] = x;
- x >>= 8;
- }
- mf_set_value(field, &value, rule);
- } else {
- union mf_value value, mask;
- uint8_t *vp = (uint8_t *) &value;
- uint8_t *mp = (uint8_t *) &mask;
-
- mf_get(field, rule, &value, &mask);
- bitwise_put(x, vp, field->n_bytes, ofs, n_bits);
- bitwise_put(UINT64_MAX, mp, field->n_bytes, ofs, n_bits);
- mf_set(field, &value, &mask, rule);
- }
-}
-
-/* Similar to mf_set_subfield() but modifies only a flow, not a cls_rule. */
-void
-mf_set_subfield_value(const struct mf_subfield *sf, uint64_t x,
- struct flow *flow)
-{
- const struct mf_field *field = sf->field;
- unsigned int n_bits = sf->n_bits;
- unsigned int ofs = sf->ofs;
- union mf_value value;
-
- if (ofs == 0 && field->n_bytes * 8 == n_bits) {
- int i;
-
- for (i = field->n_bytes - 1; i >= 0; i--) {
- ((uint8_t *) &value)[i] = x;
- x >>= 8;
- }
- mf_set_flow_value(field, &value, flow);
- } else {
- mf_get_value(field, flow, &value);
- bitwise_put(x, &value, field->n_bytes, ofs, n_bits);
- mf_set_flow_value(field, &value, flow);
- }
-}
-
/* Initializes 'x' to the value of 'sf' within 'flow'. 'sf' must be valid for
* reading 'flow', e.g. as checked by mf_check_src(). */
void