From 47284b1fc6fe84a9b5b43b49bef868e4eb230cd1 Mon Sep 17 00:00:00 2001 From: Ansis Atteka Date: Wed, 25 Apr 2012 15:48:40 -0700 Subject: [PATCH] nicira-ext: Support masking of nd_target field This commit adds support to specify a mask in CIDR format for the nd_target field. Signed-off-by: Ansis Atteka --- NEWS | 2 ++ include/openflow/nicira-ext.h | 6 ++++-- lib/classifier.c | 26 ++++++++++++++---------- lib/classifier.h | 2 ++ lib/flow.c | 37 +++++++++++++++++++++++------------ lib/flow.h | 17 ++++++++-------- lib/learn.c | 2 +- lib/meta-flow.c | 18 ++++++++++++----- lib/nx-match.c | 8 +++----- lib/nx-match.h | 8 ++++---- lib/ofp-util.c | 8 ++++---- tests/ovs-ofctl.at | 4 ++++ utilities/ovs-ofctl.8.in | 2 +- 13 files changed, 87 insertions(+), 53 deletions(-) diff --git a/NEWS b/NEWS index e717a4a40..723c256cb 100644 --- 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. diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index f8b863c9b..ccd627398 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -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. diff --git a/lib/classifier.c b/lib/classifier.c index 122a6c6e9..30cc31d32 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -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)); } diff --git a/lib/classifier.h b/lib/classifier.h index 84cb6028d..48eb59629 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -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); diff --git a/lib/flow.c b/lib/flow.c index 4d472312b..ef1dd6d20 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -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 diff --git a/lib/flow.h b/lib/flow.h index 5b389bcac..41e63865f 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -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 *); diff --git a/lib/learn.c b/lib/learn.c index 480ad909f..7f30f6ee0 100644 --- a/lib/learn.c +++ b/lib/learn.c @@ -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); } } } diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 3db528fb7..69226cbcf 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -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; diff --git a/lib/nx-match.c b/lib/nx-match.c index 0e61d3525..91dd7fc50 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -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); diff --git a/lib/nx-match.h b/lib/nx-match.h index 592d46fb8..296a63a05 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -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); -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. */ diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 90475f7ae..ae9b30d31 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -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. */ diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index a52382eaa..37498a743 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -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 diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index d1d82c50b..18769290d 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -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 -- 2.43.0