nicira-ext: Support masking of nd_target field
authorAnsis Atteka <aatteka@nicira.com>
Wed, 25 Apr 2012 22:48:40 +0000 (15:48 -0700)
committerAnsis Atteka <aatteka@nicira.com>
Thu, 26 Apr 2012 22:22:48 +0000 (15:22 -0700)
This commit adds support to specify a mask in CIDR format for
the nd_target field.

Signed-off-by: Ansis Atteka <aatteka@nicira.com>
13 files changed:
NEWS
include/openflow/nicira-ext.h
lib/classifier.c
lib/classifier.h
lib/flow.c
lib/flow.h
lib/learn.c
lib/meta-flow.c
lib/nx-match.c
lib/nx-match.h
lib/ofp-util.c
tests/ovs-ofctl.at
utilities/ovs-ofctl.8.in

diff --git a/NEWS b/NEWS
index e717a4a..723c256 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ post-v1.6.0
       Internetwork Control (0xc0).
     - Added the granular link health statistics, 'cfm_health', to an
       interface.
+    - OpenFlow:
+        - Added support to mask nd_target for ICMPv6 neighbor discovery flows.
     - ovs-test:
         - Added support for spawning ovs-test server from the client.
         - Now ovs-test is able to automatically create test bridges and ports.
index f8b863c..ccd6273 100644 (file)
@@ -1634,8 +1634,10 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
  *
  * Format: 128-bit IPv6 address.
  *
- * Masking: Not maskable. */
-#define NXM_NX_ND_TARGET   NXM_HEADER  (0x0001, 23, 16)
+ * Masking: Only CIDR masks are allowed, that is, masks that consist of N
+ *   high-order bits set to 1 and the other 128-N bits set to 0. */
+#define NXM_NX_ND_TARGET     NXM_HEADER    (0x0001, 23, 16)
+#define NXM_NX_ND_TARGET_W   NXM_HEADER_W  (0x0001, 23, 16)
 
 /* The source link-layer address option in an IPv6 Neighbor Discovery
  * message.
index 122a6c6..30cc31d 100644 (file)
@@ -415,8 +415,17 @@ cls_rule_set_ipv6_label(struct cls_rule *rule, ovs_be32 ipv6_label)
 void
 cls_rule_set_nd_target(struct cls_rule *rule, const struct in6_addr *target)
 {
-    rule->wc.wildcards &= ~FWW_ND_TARGET;
     rule->flow.nd_target = *target;
+    rule->wc.nd_target_mask = in6addr_exact;
+}
+
+void
+cls_rule_set_nd_target_masked(struct cls_rule *rule,
+                              const struct in6_addr *target,
+                              const struct in6_addr *mask)
+{
+    rule->flow.nd_target = ipv6_addr_bitand(target, mask);
+    rule->wc.nd_target_mask = *mask;
 }
 
 /* Returns true if 'a' and 'b' have the same priority, wildcard the same
@@ -491,7 +500,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     if (rule->priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%d,", rule->priority);
@@ -669,11 +678,8 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
     } else if (f->nw_proto == IPPROTO_ICMPV6) {
         format_be16_masked(s, "icmp_type", f->tp_src, wc->tp_src_mask);
         format_be16_masked(s, "icmp_code", f->tp_dst, wc->tp_dst_mask);
-        if (!(w & FWW_ND_TARGET)) {
-            ds_put_cstr(s, "nd_target=");
-            print_ipv6_addr(s, &f->nd_target);
-            ds_put_char(s, ',');
-        }
+        format_ipv6_netmask(s, "nd_target", &f->nd_target,
+                            &wc->nd_target_mask);
         if (!(w & FWW_ARP_SHA)) {
             ds_put_format(s, "nd_sll="ETH_ADDR_FMT",",
                     ETH_ADDR_ARGS(f->arp_sha));
@@ -1173,7 +1179,7 @@ flow_equal_except(const struct flow *a, const struct flow *b,
     const flow_wildcards_t wc = wildcards->wildcards;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) {
@@ -1211,6 +1217,6 @@ flow_equal_except(const struct flow *a, const struct flow *b,
                     &wildcards->ipv6_src_mask)
             && ipv6_equal_except(&a->ipv6_dst, &b->ipv6_dst,
                     &wildcards->ipv6_dst_mask)
-            && (wc & FWW_ND_TARGET
-                || ipv6_addr_equals(&a->nd_target, &b->nd_target)));
+            && ipv6_equal_except(&a->nd_target, &b->nd_target,
+                                 &wildcards->nd_target_mask));
 }
index 84cb602..48eb596 100644 (file)
@@ -135,6 +135,8 @@ void cls_rule_set_ipv6_dst_masked(struct cls_rule *, const struct in6_addr *,
                                   const struct in6_addr *);
 void cls_rule_set_ipv6_label(struct cls_rule *, ovs_be32);
 void cls_rule_set_nd_target(struct cls_rule *, const struct in6_addr *);
+void cls_rule_set_nd_target_masked(struct cls_rule *, const struct in6_addr *,
+                                   const struct in6_addr *);
 
 bool cls_rule_equal(const struct cls_rule *, const struct cls_rule *);
 uint32_t cls_rule_hash(const struct cls_rule *, uint32_t basis);
index 4d47231..ef1dd6d 100644 (file)
@@ -444,7 +444,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
     const flow_wildcards_t wc = wildcards->wildcards;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         flow->regs[i] &= wildcards->reg_masks[i];
@@ -497,9 +497,8 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
             &wildcards->ipv6_src_mask);
     flow->ipv6_dst = ipv6_addr_bitand(&flow->ipv6_dst,
             &wildcards->ipv6_dst_mask);
-    if (wc & FWW_ND_TARGET) {
-        memset(&flow->nd_target, 0, sizeof flow->nd_target);
-    }
+    flow->nd_target = ipv6_addr_bitand(&flow->nd_target,
+            &wildcards->nd_target_mask);
     flow->skb_priority = 0;
 }
 
@@ -507,7 +506,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
 void
 flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     fmd->tun_id = flow->tun_id;
     fmd->tun_id_mask = htonll(UINT64_MAX);
@@ -596,7 +595,7 @@ flow_print(FILE *stream, const struct flow *flow)
 void
 flow_wildcards_init_catchall(struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     wc->wildcards = FWW_ALL;
     wc->tun_id_mask = htonll(0);
@@ -604,6 +603,7 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc)
     wc->nw_dst_mask = htonl(0);
     wc->ipv6_src_mask = in6addr_any;
     wc->ipv6_dst_mask = in6addr_any;
+    wc->nd_target_mask = in6addr_any;
     memset(wc->reg_masks, 0, sizeof wc->reg_masks);
     wc->vlan_tci_mask = htons(0);
     wc->nw_frag_mask = 0;
@@ -617,7 +617,7 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc)
 void
 flow_wildcards_init_exact(struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     wc->wildcards = 0;
     wc->tun_id_mask = htonll(UINT64_MAX);
@@ -625,6 +625,7 @@ flow_wildcards_init_exact(struct flow_wildcards *wc)
     wc->nw_dst_mask = htonl(UINT32_MAX);
     wc->ipv6_src_mask = in6addr_exact;
     wc->ipv6_dst_mask = in6addr_exact;
+    wc->nd_target_mask = in6addr_exact;
     memset(wc->reg_masks, 0xff, sizeof wc->reg_masks);
     wc->vlan_tci_mask = htons(UINT16_MAX);
     wc->nw_frag_mask = UINT8_MAX;
@@ -640,7 +641,7 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc)
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     if (wc->wildcards
         || wc->tun_id_mask != htonll(UINT64_MAX)
@@ -651,6 +652,7 @@ flow_wildcards_is_exact(const struct flow_wildcards *wc)
         || wc->vlan_tci_mask != htons(UINT16_MAX)
         || !ipv6_mask_is_exact(&wc->ipv6_src_mask)
         || !ipv6_mask_is_exact(&wc->ipv6_dst_mask)
+        || !ipv6_mask_is_exact(&wc->nd_target_mask)
         || wc->nw_frag_mask != UINT8_MAX) {
         return false;
     }
@@ -671,7 +673,7 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc)
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     if (wc->wildcards != FWW_ALL
         || wc->tun_id_mask != htonll(0)
@@ -682,6 +684,7 @@ flow_wildcards_is_catchall(const struct flow_wildcards *wc)
         || wc->vlan_tci_mask != htons(0)
         || !ipv6_mask_is_any(&wc->ipv6_src_mask)
         || !ipv6_mask_is_any(&wc->ipv6_dst_mask)
+        || !ipv6_mask_is_any(&wc->nd_target_mask)
         || wc->nw_frag_mask != 0) {
         return false;
     }
@@ -705,7 +708,7 @@ flow_wildcards_combine(struct flow_wildcards *dst,
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     dst->wildcards = src1->wildcards | src2->wildcards;
     dst->tun_id_mask = src1->tun_id_mask & src2->tun_id_mask;
@@ -715,6 +718,8 @@ flow_wildcards_combine(struct flow_wildcards *dst,
                                         &src2->ipv6_src_mask);
     dst->ipv6_dst_mask = ipv6_addr_bitand(&src1->ipv6_dst_mask,
                                         &src2->ipv6_dst_mask);
+    dst->nd_target_mask = ipv6_addr_bitand(&src1->nd_target_mask,
+                                        &src2->nd_target_mask);
     for (i = 0; i < FLOW_N_REGS; i++) {
         dst->reg_masks[i] = src1->reg_masks[i] & src2->reg_masks[i];
     }
@@ -730,7 +735,7 @@ flow_wildcards_hash(const struct flow_wildcards *wc, uint32_t basis)
     /* If you change struct flow_wildcards and thereby trigger this
      * assertion, please check that the new struct flow_wildcards has no holes
      * in it before you update the assertion. */
-    BUILD_ASSERT_DECL(sizeof *wc == 64 + FLOW_N_REGS * 4);
+    BUILD_ASSERT_DECL(sizeof *wc == 80 + FLOW_N_REGS * 4);
     return hash_bytes(wc, sizeof *wc, basis);
 }
 
@@ -742,7 +747,7 @@ flow_wildcards_equal(const struct flow_wildcards *a,
 {
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     if (a->wildcards != b->wildcards
         || a->tun_id_mask != b->tun_id_mask
@@ -751,6 +756,7 @@ flow_wildcards_equal(const struct flow_wildcards *a,
         || a->vlan_tci_mask != b->vlan_tci_mask
         || !ipv6_addr_equals(&a->ipv6_src_mask, &b->ipv6_src_mask)
         || !ipv6_addr_equals(&a->ipv6_dst_mask, &b->ipv6_dst_mask)
+        || !ipv6_addr_equals(&a->nd_target_mask, &b->nd_target_mask)
         || a->tp_src_mask != b->tp_src_mask
         || a->tp_dst_mask != b->tp_dst_mask) {
         return false;
@@ -774,7 +780,7 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
     int i;
     struct in6_addr ipv6_masked;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         if ((a->reg_masks[i] & b->reg_masks[i]) != b->reg_masks[i]) {
@@ -792,6 +798,11 @@ flow_wildcards_has_extra(const struct flow_wildcards *a,
         return true;
     }
 
+    ipv6_masked = ipv6_addr_bitand(&a->nd_target_mask, &b->nd_target_mask);
+    if (!ipv6_addr_equals(&ipv6_masked, &b->nd_target_mask)) {
+        return true;
+    }
+
     return (a->wildcards & ~b->wildcards
             || (a->tun_id_mask & b->tun_id_mask) != b->tun_id_mask
             || (a->nw_src_mask & b->nw_src_mask) != b->nw_src_mask
index 5b389bc..41e6386 100644 (file)
@@ -35,7 +35,7 @@ struct ofpbuf;
 /* This sequence number should be incremented whenever anything involving flows
  * or the wildcarding of flows changes.  This will cause build assertion
  * failures in places which likely need to be updated. */
-#define FLOW_WC_SEQ 9
+#define FLOW_WC_SEQ 10
 
 #define FLOW_N_REGS 8
 BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
@@ -100,7 +100,7 @@ BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nw_frag) == 1);
 BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE);
 
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
-BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 142 && FLOW_WC_SEQ == 9);
+BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 142 && FLOW_WC_SEQ == 10);
 
 void flow_extract(struct ofpbuf *, uint32_t priority, ovs_be64 tun_id,
                   uint16_t in_port, struct flow *);
@@ -159,13 +159,12 @@ typedef unsigned int OVS_BITWISE flow_wildcards_t;
 #define FWW_NW_ECN      ((OVS_FORCE flow_wildcards_t) (1 << 7))
 #define FWW_ARP_SHA     ((OVS_FORCE flow_wildcards_t) (1 << 8))
 #define FWW_ARP_THA     ((OVS_FORCE flow_wildcards_t) (1 << 9))
-#define FWW_ND_TARGET   ((OVS_FORCE flow_wildcards_t) (1 << 10))
-#define FWW_IPV6_LABEL  ((OVS_FORCE flow_wildcards_t) (1 << 11))
-#define FWW_NW_TTL      ((OVS_FORCE flow_wildcards_t) (1 << 12))
-#define FWW_ALL         ((OVS_FORCE flow_wildcards_t) (((1 << 13)) - 1))
+#define FWW_IPV6_LABEL  ((OVS_FORCE flow_wildcards_t) (1 << 10))
+#define FWW_NW_TTL      ((OVS_FORCE flow_wildcards_t) (1 << 11))
+#define FWW_ALL         ((OVS_FORCE flow_wildcards_t) (((1 << 12)) - 1))
 
 /* Remember to update FLOW_WC_SEQ when adding or removing FWW_*. */
-BUILD_ASSERT_DECL(FWW_ALL == ((1 << 13) - 1) && FLOW_WC_SEQ == 9);
+BUILD_ASSERT_DECL(FWW_ALL == ((1 << 12) - 1) && FLOW_WC_SEQ == 10);
 
 /* Information on wildcards for a flow, as a supplement to "struct flow".
  *
@@ -179,6 +178,8 @@ struct flow_wildcards {
     ovs_be32 nw_dst_mask;       /* 1-bit in each significant nw_dst bit. */
     struct in6_addr ipv6_src_mask; /* 1-bit in each signficant ipv6_src bit. */
     struct in6_addr ipv6_dst_mask; /* 1-bit in each signficant ipv6_dst bit. */
+    struct in6_addr nd_target_mask; /* 1-bit in each significant
+                                       nd_target bit. */
     ovs_be16 vlan_tci_mask;     /* 1-bit in each significant vlan_tci bit. */
     ovs_be16 tp_src_mask;       /* 1-bit in each significant tp_src bit. */
     ovs_be16 tp_dst_mask;       /* 1-bit in each significant tp_dst bit. */
@@ -187,7 +188,7 @@ struct flow_wildcards {
 };
 
 /* Remember to update FLOW_WC_SEQ when updating struct flow_wildcards. */
-BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 96 && FLOW_WC_SEQ == 9);
+BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 112 && FLOW_WC_SEQ == 10);
 
 void flow_wildcards_init_catchall(struct flow_wildcards *);
 void flow_wildcards_init_exact(struct flow_wildcards *);
index 480ad90..7f30f6e 100644 (file)
@@ -184,7 +184,7 @@ learn_check(const struct nx_action_learn *learn, const struct flow *flow)
                      * prerequisites.  No prerequisite depends on the value of
                      * a field that is wider than 64 bits.  So just skip
                      * setting it entirely. */
-                    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+                    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
                 }
             }
         }
index 3db528f..69226cb 100644 (file)
@@ -407,7 +407,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
     {
         MFF_ND_TARGET, "nd_target", NULL,
         MF_FIELD_SIZES(ipv6),
-        MFM_NONE, FWW_ND_TARGET,
+        MFM_CIDR, 0,
         MFS_IPV6,
         MFP_ND,
         false,
@@ -553,7 +553,6 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
     case MFF_ARP_OP:
     case MFF_ARP_SHA:
     case MFF_ARP_THA:
-    case MFF_ND_TARGET:
     case MFF_ND_SLL:
     case MFF_ND_TLL:
         assert(mf->fww_bit != 0);
@@ -612,6 +611,9 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
     case MFF_IPV6_DST:
         return ipv6_mask_is_any(&wc->ipv6_dst_mask);
 
+    case MFF_ND_TARGET:
+        return ipv6_mask_is_any(&wc->nd_target_mask);
+
     case MFF_IP_FRAG:
         return !(wc->nw_frag_mask & FLOW_NW_FRAG_MASK);
 
@@ -659,7 +661,6 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
     case MFF_ARP_OP:
     case MFF_ARP_SHA:
     case MFF_ARP_THA:
-    case MFF_ND_TARGET:
     case MFF_ND_SLL:
     case MFF_ND_TLL:
         assert(mf->fww_bit != 0);
@@ -729,6 +730,10 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
         mask->ipv6 = wc->ipv6_dst_mask;
         break;
 
+    case MFF_ND_TARGET:
+        mask->ipv6 = wc->nd_target_mask;
+        break;
+
     case MFF_IP_FRAG:
         mask->u8 = wc->nw_frag_mask & FLOW_NW_FRAG_MASK;
         break;
@@ -1624,7 +1629,7 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule)
         break;
 
     case MFF_ND_TARGET:
-        rule->wc.wildcards |= FWW_ND_TARGET;
+        memset(&rule->wc.nd_target_mask, 0, sizeof rule->wc.nd_target_mask);
         memset(&rule->flow.nd_target, 0, sizeof rule->flow.nd_target);
         break;
 
@@ -1676,7 +1681,6 @@ mf_set(const struct mf_field *mf,
     case MFF_ICMPV4_CODE:
     case MFF_ICMPV6_TYPE:
     case MFF_ICMPV6_CODE:
-    case MFF_ND_TARGET:
     case MFF_ND_SLL:
     case MFF_ND_TLL:
         NOT_REACHED();
@@ -1742,6 +1746,10 @@ mf_set(const struct mf_field *mf,
         cls_rule_set_ipv6_dst_masked(rule, &value->ipv6, &mask->ipv6);
         break;
 
+    case MFF_ND_TARGET:
+        cls_rule_set_nd_target_masked(rule, &value->ipv6, &mask->ipv6);
+        break;
+
     case MFF_IP_FRAG:
         cls_rule_set_nw_frag_masked(rule, value->u8, mask->u8);
         break;
index 0e61d35..91dd7fc 100644 (file)
@@ -471,7 +471,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr,
     int match_len;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     /* Metadata. */
     if (!(wc & FWW_IN_PORT)) {
@@ -514,10 +514,8 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr,
         if (flow->nw_proto == IPPROTO_ICMPV6
             && (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
                 flow->tp_src == htons(ND_NEIGHBOR_ADVERT))) {
-            if (!(wc & FWW_ND_TARGET)) {
-                nxm_put_ipv6(b, NXM_NX_ND_TARGET, &flow->nd_target,
-                             &in6addr_exact);
-            }
+            nxm_put_ipv6(b, NXM_NX_ND_TARGET, &flow->nd_target,
+                         &cr->wc.nd_target_mask);
             if (!(wc & FWW_ARP_SHA)
                 && flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
                 nxm_put_eth(b, NXM_NX_ND_SLL, flow->arp_sha);
index 592d46f..296a63a 100644 (file)
@@ -90,7 +90,7 @@ void nxm_decode(struct mf_subfield *, ovs_be32 header, ovs_be16 ofs_nbits);
 void nxm_decode_discrete(struct mf_subfield *, ovs_be32 header,
                          ovs_be16 ofs, ovs_be16 n_bits);
 \f
-BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 /* Upper bound on the length of an nx_match.  The longest nx_match (an
  * IPV6 neighbor discovery message using 5 registers) would be:
  *
@@ -111,7 +111,7 @@ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
  *  NXM_OF_IPV6_LABEL   4       4    --      8
  *  NXM_OF_ICMP_TYPE    4       1    --      5
  *  NXM_OF_ICMP_CODE    4       1    --      5
- *  NXM_NX_ND_TARGET    4      16    --     20
+ *  NXM_NX_ND_TARGET    4      16    16     36
  *  NXM_NX_ND_SLL       4       6    --     10
  *  NXM_NX_REG_W(0)     4       4     4     12
  *  NXM_NX_REG_W(1)     4       4     4     12
@@ -123,11 +123,11 @@ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
  *  NXM_NX_REG_W(7)     4       4     4     12
  *  NXM_NX_TUN_ID_W     4       8     8     20
  *  -------------------------------------------
- *  total                                  311
+ *  total                                  327
  *
  * So this value is conservative.
  */
-#define NXM_MAX_LEN 384
+#define NXM_MAX_LEN 400
 
 /* This is my guess at the length of a "typical" nx_match, for use in
  * predicting space requirements. */
index 90475f7..ae9b30d 100644 (file)
@@ -101,7 +101,7 @@ static const flow_wildcards_t WC_INVARIANTS = 0
 void
 ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     /* Initialize most of rule->wc. */
     flow_wildcards_init_catchall(wc);
@@ -109,7 +109,7 @@ ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *wc)
 
     /* Wildcard fields that aren't defined by ofp_match or tun_id. */
     wc->wildcards |= (FWW_ARP_SHA | FWW_ARP_THA | FWW_NW_ECN | FWW_NW_TTL
-                      | FWW_ND_TARGET | FWW_IPV6_LABEL);
+                      | FWW_IPV6_LABEL);
 
     if (ofpfw & OFPFW_NW_TOS) {
         /* OpenFlow 1.0 defines a TOS wildcard, but it's much later in
@@ -1166,7 +1166,7 @@ ofputil_usable_protocols(const struct cls_rule *rule)
 {
     const struct flow_wildcards *wc = &rule->wc;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 9);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 10);
 
     /* Only NXM supports separately wildcards the Ethernet multicast bit. */
     if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) {
@@ -3810,7 +3810,7 @@ ofputil_normalize_rule(struct cls_rule *rule)
         wc.wildcards |= FWW_IPV6_LABEL;
     }
     if (!(may_match & MAY_ND_TARGET)) {
-        wc.wildcards |= FWW_ND_TARGET;
+        wc.nd_target_mask = in6addr_any;
     }
 
     /* Log any changes. */
index a52382e..37498a7 100644 (file)
@@ -109,8 +109,10 @@ udp dl_vlan_pcp=7 idle_timeout=5 actions=strip_vlan output:0
 tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
 udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
 icmp6,icmp_type=135,nd_target=FEC0::1234:F045:8FFF:1111:FE4E:0571 actions=drop
+icmp6,icmp_type=135,nd_target=FEC0::1234:F045:8FFF:1111:FE4F:0571/112 actions=drop
 icmp6,icmp_type=135,nd_sll=00:0A:E4:25:6B:B0 actions=drop
 icmp6,icmp_type=136,nd_target=FEC0::1234:F045:8FFF:1111:FE4E:0571,nd_tll=00:0A:E4:25:6B:B1 actions=drop
+icmp6,icmp_type=136,nd_target=FEC0::1234:F045:8FFF:1111:FE00:0000/96,nd_tll=00:0A:E4:25:6B:B1 actions=drop
 cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
 actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
 tun_id=0x1234,cookie=0x5678,actions=flood
@@ -139,8 +141,10 @@ NXT_FLOW_MOD: ADD udp,dl_vlan_pcp=7 idle:5 actions=strip_vlan,output:0
 NXT_FLOW_MOD: ADD tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
 NXT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
 NXT_FLOW_MOD: ADD icmp6,icmp_type=135,nd_target=fec0:0:1234:f045:8fff:1111:fe4e:571 actions=drop
+NXT_FLOW_MOD: ADD icmp6,icmp_type=135,nd_target=fec0:0:1234:f045:8fff:1111:fe4f:0/112 actions=drop
 NXT_FLOW_MOD: ADD icmp6,icmp_type=135,nd_sll=00:0a:e4:25:6b:b0 actions=drop
 NXT_FLOW_MOD: ADD icmp6,icmp_type=136,nd_target=fec0:0:1234:f045:8fff:1111:fe4e:571,nd_tll=00:0a:e4:25:6b:b1 actions=drop
+NXT_FLOW_MOD: ADD icmp6,icmp_type=136,nd_target=fec0:0:1234:f045:8fff:1111::/96,nd_tll=00:0a:e4:25:6b:b1 actions=drop
 NXT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
 NXT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
 NXT_FLOW_MOD: ADD tun_id=0x1234 cookie:0x5678 actions=FLOOD
index d1d82c5..1876929 100644 (file)
@@ -654,7 +654,7 @@ as a CIDR block (e.g. \fB2001:db8:3c4d:1::/64\fR).
 When \fBdl_type\fR is 0x86dd (possibly via shorthand, e.g., \fBipv6\fR
 or \fBtcp6\fR), matches IPv6 flow label \fIlabel\fR.
 .
-.IP \fBnd_target=\fIipv6\fR
+.IP \fBnd_target=\fIipv6\fR[\fB/\fInetmask\fR]
 When \fBdl_type\fR, \fBnw_proto\fR, and \fBicmp_type\fR specify
 IPv6 Neighbor Discovery (ICMPv6 type 135 or 136), matches the target address
 \fIipv6\fR.  \fIipv6\fR is in the same format described earlier for the