+/* "Normalizes" the wildcards in 'rule'. That means:
+ *
+ * 1. If the type of level N is known, then only the valid fields for that
+ * level may be specified. For example, ARP does not have a TOS field,
+ * so nw_tos must be wildcarded if 'rule' specifies an ARP flow.
+ * Similarly, IPv4 does not have any IPv6 addresses, so ipv6_src and
+ * ipv6_dst (and other fields) must be wildcarded if 'rule' specifies an
+ * IPv4 flow.
+ *
+ * 2. If the type of level N is not known (or not understood by Open
+ * vSwitch), then no fields at all for that level may be specified. For
+ * example, Open vSwitch does not understand SCTP, an L4 protocol, so the
+ * L4 fields tp_src and tp_dst must be wildcarded if 'rule' specifies an
+ * SCTP flow.
+ *
+ * 'flow_format' specifies the format of the flow as received or as intended to
+ * be sent. This is important for IPv6 and ARP, for which NXM supports more
+ * detailed matching. */
+void
+ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
+{
+ enum {
+ MAY_NW_ADDR = 1 << 0, /* nw_src, nw_dst */
+ MAY_TP_ADDR = 1 << 1, /* tp_src, tp_dst */
+ MAY_NW_PROTO = 1 << 2, /* nw_proto */
+ MAY_NW_TOS = 1 << 3, /* nw_tos */
+ MAY_ARP_SHA = 1 << 4, /* arp_sha */
+ MAY_ARP_THA = 1 << 5, /* arp_tha */
+ MAY_IPV6_ADDR = 1 << 6, /* ipv6_src, ipv6_dst */
+ MAY_ND_TARGET = 1 << 7 /* nd_target */
+ } may_match;
+
+ struct flow_wildcards wc;
+
+ /* Figure out what fields may be matched. */
+ if (rule->flow.dl_type == htons(ETH_TYPE_IP)) {
+ may_match = MAY_NW_PROTO | MAY_NW_TOS | MAY_NW_ADDR;
+ if (rule->flow.nw_proto == IPPROTO_TCP ||
+ rule->flow.nw_proto == IPPROTO_UDP ||
+ rule->flow.nw_proto == IPPROTO_ICMP) {
+ may_match |= MAY_TP_ADDR;
+ }
+ } else if (rule->flow.dl_type == htons(ETH_TYPE_IPV6)
+ && flow_format == NXFF_NXM) {
+ may_match = MAY_NW_PROTO | MAY_NW_TOS | MAY_IPV6_ADDR;
+ if (rule->flow.nw_proto == IPPROTO_TCP ||
+ rule->flow.nw_proto == IPPROTO_UDP) {
+ may_match |= MAY_TP_ADDR;
+ } else if (rule->flow.nw_proto == IPPROTO_ICMPV6) {
+ may_match |= MAY_TP_ADDR;
+ if (rule->flow.tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
+ may_match |= MAY_ND_TARGET | MAY_ARP_SHA;
+ } else if (rule->flow.tp_src == htons(ND_NEIGHBOR_ADVERT)) {
+ may_match |= MAY_ND_TARGET | MAY_ARP_THA;
+ }
+ }
+ } else if (rule->flow.dl_type == htons(ETH_TYPE_ARP)) {
+ may_match = MAY_NW_PROTO | MAY_NW_ADDR;
+ if (flow_format == NXFF_NXM) {
+ may_match |= MAY_ARP_SHA | MAY_ARP_THA;