-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_be32(maskp))
- : UINT32_MAX));
- flow->regs[idx] = ntohl(get_unaligned_be32(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_be16(value));
- return 0;
-
- /* Ethernet header. */
- case NFI_NXM_OF_ETH_DST:
- if ((wc->wildcards & (FWW_DL_DST | FWW_ETH_MCAST))
- != (FWW_DL_DST | FWW_ETH_MCAST)) {
- return NXM_DUP_TYPE;
- } else {
- 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 & (FWW_DL_DST | FWW_ETH_MCAST))
- != (FWW_DL_DST | FWW_ETH_MCAST)) {
- return NXM_DUP_TYPE;
- } else if (flow_wildcards_is_dl_dst_mask_valid(mask)) {
- cls_rule_set_dl_dst_masked(rule, value, mask);
- 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 = ofputil_dl_type_from_openflow(get_unaligned_be16(value));
- return 0;
-
- /* 802.1Q header. */
- case NFI_NXM_OF_VLAN_TCI:
- 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:
- 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 (*(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_be32(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_be32(value);
- ovs_be32 netmask = get_unaligned_be32(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_be32(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_be32(value);
- ovs_be32 netmask = get_unaligned_be32(mask);
- if (!cls_rule_set_nw_dst_masked(rule, ip, netmask)) {
- return NXM_BAD_MASK;
- }
- return 0;
- }
-
- /* IPv6 addresses. */
- case NFI_NXM_NX_IPV6_SRC:
- if (!ipv6_mask_is_any(&wc->ipv6_src_mask)) {
- return NXM_DUP_TYPE;
- } else {
- struct in6_addr ipv6;
- memcpy(&ipv6, value, sizeof ipv6);
- cls_rule_set_ipv6_src(rule, &ipv6);
- return 0;
- }
- case NFI_NXM_NX_IPV6_SRC_W:
- if (!ipv6_mask_is_any(&wc->ipv6_src_mask)) {
- return NXM_DUP_TYPE;
- } else {
- struct in6_addr ipv6, netmask;
- memcpy(&ipv6, value, sizeof ipv6);
- memcpy(&netmask, mask, sizeof netmask);
- if (!cls_rule_set_ipv6_src_masked(rule, &ipv6, &netmask)) {
- return NXM_BAD_MASK;
- }
- return 0;
- }
- case NFI_NXM_NX_IPV6_DST:
- if (!ipv6_mask_is_any(&wc->ipv6_dst_mask)) {
- return NXM_DUP_TYPE;
- } else {
- struct in6_addr ipv6;
- memcpy(&ipv6, value, sizeof ipv6);
- cls_rule_set_ipv6_dst(rule, &ipv6);
- return 0;
- }
- case NFI_NXM_NX_IPV6_DST_W:
- if (!ipv6_mask_is_any(&wc->ipv6_dst_mask)) {
- return NXM_DUP_TYPE;
- } else {
- struct in6_addr ipv6, netmask;
- memcpy(&ipv6, value, sizeof ipv6);
- memcpy(&netmask, mask, sizeof netmask);
- if (!cls_rule_set_ipv6_dst_masked(rule, &ipv6, &netmask)) {
- return NXM_BAD_MASK;
- }
- return 0;
- }
-
- /* TCP header. */
- case NFI_NXM_OF_TCP_SRC:
- flow->tp_src = get_unaligned_be16(value);
- return 0;
- case NFI_NXM_OF_TCP_DST:
- flow->tp_dst = get_unaligned_be16(value);
- return 0;
-
- /* UDP header. */
- case NFI_NXM_OF_UDP_SRC:
- flow->tp_src = get_unaligned_be16(value);
- return 0;
- case NFI_NXM_OF_UDP_DST:
- flow->tp_dst = get_unaligned_be16(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;
-
- /* ICMPv6 header. */
- case NFI_NXM_NX_ICMPV6_TYPE:
- flow->tp_src = htons(*(uint8_t *) value);
- return 0;
- case NFI_NXM_NX_ICMPV6_CODE:
- flow->tp_dst = htons(*(uint8_t *) value);
- return 0;
-
- /* IPv6 Neighbor Discovery. */
- case NFI_NXM_NX_ND_TARGET:
- /* We've already verified that it's an ICMPv6 message. */
- if ((flow->tp_src != htons(ND_NEIGHBOR_SOLICIT))
- && (flow->tp_src != htons(ND_NEIGHBOR_ADVERT))) {
- return NXM_BAD_PREREQ;
- }
- memcpy(&flow->nd_target, value, sizeof flow->nd_target);
- return 0;
- case NFI_NXM_NX_ND_SLL:
- /* We've already verified that it's an ICMPv6 message. */
- if (flow->tp_src != htons(ND_NEIGHBOR_SOLICIT)) {
- return NXM_BAD_PREREQ;
- }
- memcpy(flow->arp_sha, value, ETH_ADDR_LEN);
- return 0;
- case NFI_NXM_NX_ND_TLL:
- /* We've already verified that it's an ICMPv6 message. */
- if (flow->tp_src != htons(ND_NEIGHBOR_ADVERT)) {
- return NXM_BAD_PREREQ;
- }
- memcpy(flow->arp_tha, value, ETH_ADDR_LEN);
- return 0;
-
- /* ARP header. */
- case NFI_NXM_OF_ARP_OP:
- if (ntohs(get_unaligned_be16(value)) > 255) {
- return NXM_BAD_VALUE;
- } else {
- flow->nw_proto = ntohs(get_unaligned_be16(value));
- return 0;
- }
-
- case NFI_NXM_NX_ARP_SHA:
- memcpy(flow->arp_sha, value, ETH_ADDR_LEN);
- return 0;
- case NFI_NXM_NX_ARP_THA:
- memcpy(flow->arp_tha, value, ETH_ADDR_LEN);
- return 0;
-
- /* Tunnel ID. */
- case NFI_NXM_NX_TUN_ID:
- if (wc->tun_id_mask) {
- return NXM_DUP_TYPE;
- } else {
- cls_rule_set_tun_id(rule, get_unaligned_be64(value));
- return 0;
- }
- case NFI_NXM_NX_TUN_ID_W:
- if (wc->tun_id_mask) {
- return NXM_DUP_TYPE;
- } else {
- ovs_be64 tun_id = get_unaligned_be64(value);
- ovs_be64 tun_mask = get_unaligned_be64(mask);
- cls_rule_set_tun_id_masked(rule, tun_id, tun_mask);
- 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)
-{
- if (field->nw_proto && field->nw_proto != flow->nw_proto) {
- return false;
- }
-
- if (!field->dl_type[0]) {
- return true;
- } else if (field->dl_type[0] == flow->dl_type) {
- return true;
- } else if (field->dl_type[1] && field->dl_type[1] == flow->dl_type) {
- return true;
- }
-
- return false;
-}
-