-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,
- const void *value, const void *maskp)
-{
- int idx = NXM_NX_REG_IDX(f->header);
- if (wc->reg_masks[idx]) {
- return NXM_DUP_TYPE;
- } else {
- flow_wildcards_set_reg_mask(wc, idx,
- (NXM_HASMASK(f->header)
- ? ntohl(get_unaligned_u32(maskp))
- : UINT32_MAX));
- flow->regs[idx] = ntohl(get_unaligned_u32(value));
- flow->regs[idx] &= wc->reg_masks[idx];
- return 0;
- }
-}
-
-static int
-parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
- const void *value, const void *mask)
-{
- struct flow_wildcards *wc = &rule->wc;
- struct flow *flow = &rule->flow;
-
- switch (f->index) {
- /* Metadata. */
- case NFI_NXM_OF_IN_PORT:
- flow->in_port = ntohs(get_unaligned_u16(value));
- if (flow->in_port == OFPP_LOCAL) {
- flow->in_port = ODPP_LOCAL;
- }
- return 0;
-
- /* Ethernet header. */
- case NFI_NXM_OF_ETH_DST:
- if ((wc->wildcards & (OFPFW_DL_DST | FWW_ETH_MCAST))
- != (OFPFW_DL_DST | FWW_ETH_MCAST)) {
- return NXM_DUP_TYPE;
- } else {
- wc->wildcards &= ~(OFPFW_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)) {
- 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;
- 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);
- memcpy(flow->dl_dst, value, ETH_ADDR_LEN);
- return 0;
- } else {
- return NXM_BAD_MASK;
- }
- case NFI_NXM_OF_ETH_SRC:
- memcpy(flow->dl_src, value, ETH_ADDR_LEN);
- return 0;
- case NFI_NXM_OF_ETH_TYPE:
- flow->dl_type = get_unaligned_u16(value);
- return 0;
-
- /* 802.1Q header. */
- case NFI_NXM_OF_VLAN_TCI:
- return parse_tci(rule, get_unaligned_u16(value), htons(UINT16_MAX));
-
- case NFI_NXM_OF_VLAN_TCI_W:
- return parse_tci(rule, get_unaligned_u16(value),
- get_unaligned_u16(mask));
-
- /* IP header. */
- case NFI_NXM_OF_IP_TOS:
- if (*(uint8_t *) value & 0x03) {
- return NXM_BAD_VALUE;
- } else {
- flow->nw_tos = *(uint8_t *) value;
- return 0;
- }
- case NFI_NXM_OF_IP_PROTO:
- flow->nw_proto = *(uint8_t *) value;
- return 0;
-
- /* IP addresses in IP and ARP headers. */
- case NFI_NXM_OF_IP_SRC:
- case NFI_NXM_OF_ARP_SPA:
- if (wc->nw_src_mask) {
- return NXM_DUP_TYPE;
- } else {
- cls_rule_set_nw_src(rule, get_unaligned_u32(value));
- return 0;
- }
- case NFI_NXM_OF_IP_SRC_W:
- case NFI_NXM_OF_ARP_SPA_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);
- if (!cls_rule_set_nw_src_masked(rule, ip, netmask)) {
- return NXM_BAD_MASK;
- }
- return 0;
- }
- case NFI_NXM_OF_IP_DST:
- case NFI_NXM_OF_ARP_TPA:
- if (wc->nw_dst_mask) {
- return NXM_DUP_TYPE;
- } else {
- cls_rule_set_nw_dst(rule, get_unaligned_u32(value));
- return 0;
- }
- case NFI_NXM_OF_IP_DST_W:
- case NFI_NXM_OF_ARP_TPA_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);
- if (!cls_rule_set_nw_dst_masked(rule, ip, netmask)) {
- return NXM_BAD_MASK;
- }
- return 0;
- }
-
- /* TCP header. */
- case NFI_NXM_OF_TCP_SRC:
- flow->tp_src = get_unaligned_u16(value);
- return 0;
- case NFI_NXM_OF_TCP_DST:
- flow->tp_dst = get_unaligned_u16(value);
- return 0;
-
- /* UDP header. */
- case NFI_NXM_OF_UDP_SRC:
- flow->tp_src = get_unaligned_u16(value);
- return 0;
- case NFI_NXM_OF_UDP_DST:
- flow->tp_dst = get_unaligned_u16(value);
- return 0;
-
- /* ICMP header. */
- case NFI_NXM_OF_ICMP_TYPE:
- flow->tp_src = htons(*(uint8_t *) value);
- return 0;
- case NFI_NXM_OF_ICMP_CODE:
- flow->tp_dst = htons(*(uint8_t *) value);
- return 0;
-
- /* ARP header. */
- case NFI_NXM_OF_ARP_OP:
- if (ntohs(get_unaligned_u16(value)) > 255) {
- return NXM_BAD_VALUE;
- } else {
- flow->nw_proto = ntohs(get_unaligned_u16(value));
- return 0;
- }
-
- /* Tunnel ID. */
- case NFI_NXM_NX_TUN_ID:
- flow->tun_id = htonl(ntohll(get_unaligned_u64(value)));
- return 0;
-
- /* Registers. */
- case NFI_NXM_NX_REG0:
- case NFI_NXM_NX_REG0_W:
-#if FLOW_N_REGS >= 2
- case NFI_NXM_NX_REG1:
- case NFI_NXM_NX_REG1_W:
-#endif
-#if FLOW_N_REGS >= 3
- case NFI_NXM_NX_REG2:
- case NFI_NXM_NX_REG2_W:
-#endif
-#if FLOW_N_REGS >= 4
- case NFI_NXM_NX_REG3:
- case NFI_NXM_NX_REG3_W:
-#endif
-#if FLOW_N_REGS > 4
-#error
-#endif
- return parse_nx_reg(f, flow, wc, value, mask);
-
- case N_NXM_FIELDS:
- NOT_REACHED();
- }
- NOT_REACHED();
-}
-
-static bool
-nxm_prereqs_ok(const struct nxm_field *field, const struct flow *flow)
-{
- return (!field->dl_type
- || (field->dl_type == flow->dl_type
- && (!field->nw_proto || field->nw_proto == flow->nw_proto)));
-}
-