Thank you for the reviews. I pushed this to master, with the improvement you pointed out in patch 2.
On Thu, Feb 02, 2012 at 12:46:56PM -0800, Ethan Jackson wrote: > Looks good, > > Ethan > > On Fri, Jan 27, 2012 at 17:18, Ben Pfaff <b...@nicira.com> wrote: > > Bug #8827. > > Signed-off-by: Ben Pfaff <b...@nicira.com> > > --- > > NEWS | 3 ++ > > include/openflow/nicira-ext.h | 10 ++++- > > lib/classifier.c | 77 > > +++++++++++++++++++++++---------------- > > lib/classifier.h | 6 +++- > > lib/flow.c | 44 ++++++++++++++--------- > > lib/flow.h | 22 ++++++------ > > lib/meta-flow.c | 81 > > +++++++++++++++++++++++++---------------- > > lib/nx-match.c | 22 ++++-------- > > lib/ofp-util.c | 29 ++++++++++++--- > > tests/ovs-ofctl.at | 12 +++++- > > tests/test-classifier.c | 14 ++++++-- > > utilities/ovs-ofctl.8.in | 64 ++++++++++++++++++++++++++++++++- > > 12 files changed, 264 insertions(+), 120 deletions(-) > > > > diff --git a/NEWS b/NEWS > > index d7332f8..d7750ae 100644 > > --- a/NEWS > > +++ b/NEWS > > @@ -6,6 +6,9 @@ post-v1.5.0 > > - The default bond_mode changed from SLB to active-backup, to > > protect > > unsuspecting users from the significant risks of SLB bonds (which > > are > > documented in vswitchd/INTERNALS). > > + - OpenFlow: > > + - Added support for bitwise matching on TCP and UDP ports. > > + See ovs-ofctl(8) for more information. > > > > > > v1.5.0 - xx xxx xxxx > > diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h > > index 6921803..6d24c6c 100644 > > --- a/include/openflow/nicira-ext.h > > +++ b/include/openflow/nicira-ext.h > > @@ -1397,9 +1397,12 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == > > 24); > > * > > * Format: 16-bit integer in network byte order. > > * > > - * Masking: Not maskable. */ > > + * Masking: Fully maskable, in Open vSwitch 1.6 and later. Not maskable, > > in > > + * earlier versions. */ > > #define NXM_OF_TCP_SRC NXM_HEADER (0x0000, 9, 2) > > +#define NXM_OF_TCP_SRC_W NXM_HEADER_W(0x0000, 9, 2) > > #define NXM_OF_TCP_DST NXM_HEADER (0x0000, 10, 2) > > +#define NXM_OF_TCP_DST_W NXM_HEADER_W(0x0000, 10, 2) > > > > /* The source or destination port in the UDP header. > > * > > @@ -1409,9 +1412,12 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == > > 24); > > * > > * Format: 16-bit integer in network byte order. > > * > > - * Masking: Not maskable. */ > > + * Masking: Fully maskable, in Open vSwitch 1.6 and later. Not maskable, > > in > > + * earlier versions. */ > > #define NXM_OF_UDP_SRC NXM_HEADER (0x0000, 11, 2) > > +#define NXM_OF_UDP_SRC_W NXM_HEADER_W(0x0000, 11, 2) > > #define NXM_OF_UDP_DST NXM_HEADER (0x0000, 12, 2) > > +#define NXM_OF_UDP_DST_W NXM_HEADER_W(0x0000, 12, 2) > > > > /* The type or code in the ICMP header. > > * > > diff --git a/lib/classifier.c b/lib/classifier.c > > index 26751ca..18958a8 100644 > > --- a/lib/classifier.c > > +++ b/lib/classifier.c > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright (c) 2009, 2010, 2011 Nicira Networks. > > + * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks. > > * > > * Licensed under the Apache License, Version 2.0 (the "License"); > > * you may not use this file except in compliance with the License. > > @@ -252,15 +252,27 @@ cls_rule_set_dl_vlan_pcp(struct cls_rule *rule, > > uint8_t dl_vlan_pcp) > > void > > cls_rule_set_tp_src(struct cls_rule *rule, ovs_be16 tp_src) > > { > > - rule->wc.wildcards &= ~FWW_TP_SRC; > > - rule->flow.tp_src = tp_src; > > + cls_rule_set_tp_src_masked(rule, tp_src, htons(UINT16_MAX)); > > +} > > + > > +void > > +cls_rule_set_tp_src_masked(struct cls_rule *rule, ovs_be16 port, ovs_be16 > > mask) > > +{ > > + rule->flow.tp_src = port & mask; > > + rule->wc.tp_src_mask = mask; > > } > > > > void > > cls_rule_set_tp_dst(struct cls_rule *rule, ovs_be16 tp_dst) > > { > > - rule->wc.wildcards &= ~FWW_TP_DST; > > - rule->flow.tp_dst = tp_dst; > > + cls_rule_set_tp_dst_masked(rule, tp_dst, htons(UINT16_MAX)); > > +} > > + > > +void > > +cls_rule_set_tp_dst_masked(struct cls_rule *rule, ovs_be16 port, ovs_be16 > > mask) > > +{ > > + rule->flow.tp_dst = port & mask; > > + rule->wc.tp_dst_mask = mask; > > } > > > > void > > @@ -340,15 +352,13 @@ cls_rule_set_nw_frag_masked(struct cls_rule *rule, > > void > > cls_rule_set_icmp_type(struct cls_rule *rule, uint8_t icmp_type) > > { > > - rule->wc.wildcards &= ~FWW_TP_SRC; > > - rule->flow.tp_src = htons(icmp_type); > > + cls_rule_set_tp_src(rule, htons(icmp_type)); > > } > > > > void > > cls_rule_set_icmp_code(struct cls_rule *rule, uint8_t icmp_code) > > { > > - rule->wc.wildcards &= ~FWW_TP_DST; > > - rule->flow.tp_dst = htons(icmp_code); > > + cls_rule_set_tp_dst(rule, htons(icmp_code)); > > } > > > > void > > @@ -452,6 +462,23 @@ format_ipv6_netmask(struct ds *s, const char *name, > > } > > } > > > > + > > +static void > > +format_be16_masked(struct ds *s, const char *name, > > + ovs_be16 value, ovs_be16 mask) > > +{ > > + if (mask != htons(0)) { > > + ds_put_format(s, "%s=", name); > > + if (mask == htons(UINT16_MAX)) { > > + ds_put_format(s, "%"PRIu16, ntohs(value)); > > + } else { > > + ds_put_format(s, "0x%"PRIx16"/0x%"PRIx16, > > + ntohs(value), ntohs(mask)); > > + } > > + ds_put_char(s, ','); > > + } > > +} > > + > > void > > cls_rule_format(const struct cls_rule *rule, struct ds *s) > > { > > @@ -464,7 +491,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds > > *s) > > > > int i; > > > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > if (rule->priority != OFP_DEFAULT_PRIORITY) { > > ds_put_format(s, "priority=%d,", rule->priority); > > @@ -637,19 +664,11 @@ cls_rule_format(const struct cls_rule *rule, struct > > ds *s) > > break; > > } > > if (f->nw_proto == IPPROTO_ICMP) { > > - if (!(w & FWW_TP_SRC)) { > > - ds_put_format(s, "icmp_type=%"PRIu16",", ntohs(f->tp_src)); > > - } > > - if (!(w & FWW_TP_DST)) { > > - ds_put_format(s, "icmp_code=%"PRIu16",", ntohs(f->tp_dst)); > > - } > > + 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); > > } else if (f->nw_proto == IPPROTO_ICMPV6) { > > - if (!(w & FWW_TP_SRC)) { > > - ds_put_format(s, "icmp_type=%"PRIu16",", ntohs(f->tp_src)); > > - } > > - if (!(w & FWW_TP_DST)) { > > - ds_put_format(s, "icmp_code=%"PRIu16",", ntohs(f->tp_dst)); > > - } > > + 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); > > @@ -664,12 +683,8 @@ cls_rule_format(const struct cls_rule *rule, struct ds > > *s) > > ETH_ADDR_ARGS(f->arp_tha)); > > } > > } else { > > - if (!(w & FWW_TP_SRC)) { > > - ds_put_format(s, "tp_src=%"PRIu16",", ntohs(f->tp_src)); > > - } > > - if (!(w & FWW_TP_DST)) { > > - ds_put_format(s, "tp_dst=%"PRIu16",", ntohs(f->tp_dst)); > > - } > > + format_be16_masked(s, "tp_src", f->tp_src, wc->tp_src_mask); > > + format_be16_masked(s, "tp_dst", f->tp_dst, wc->tp_dst_mask); > > } > > > > if (s->length > start_len && ds_last(s) == ',') { > > @@ -1149,7 +1164,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 == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > for (i = 0; i < FLOW_N_REGS; i++) { > > if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) { > > @@ -1163,8 +1178,8 @@ flow_equal_except(const struct flow *a, const struct > > flow *b, > > && (wc & FWW_IN_PORT || a->in_port == b->in_port) > > && !((a->vlan_tci ^ b->vlan_tci) & wildcards->vlan_tci_mask) > > && (wc & FWW_DL_TYPE || a->dl_type == b->dl_type) > > - && (wc & FWW_TP_SRC || a->tp_src == b->tp_src) > > - && (wc & FWW_TP_DST || a->tp_dst == b->tp_dst) > > + && !((a->tp_src ^ b->tp_src) & wildcards->tp_src_mask) > > + && !((a->tp_dst ^ b->tp_dst) & wildcards->tp_dst_mask) > > && (wc & FWW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src)) > > && (wc & FWW_DL_DST > > || (!((a->dl_dst[0] ^ b->dl_dst[0]) & 0xfe) > > diff --git a/lib/classifier.h b/lib/classifier.h > > index d55475d..f9bcabb 100644 > > --- a/lib/classifier.h > > +++ b/lib/classifier.h > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright (c) 2009, 2010, 2011 Nicira Networks. > > + * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks. > > * > > * Licensed under the Apache License, Version 2.0 (the "License"); > > * you may not use this file except in compliance with the License. > > @@ -110,7 +110,11 @@ void cls_rule_set_dl_vlan(struct cls_rule *, ovs_be16); > > void cls_rule_set_any_pcp(struct cls_rule *); > > void cls_rule_set_dl_vlan_pcp(struct cls_rule *, uint8_t); > > void cls_rule_set_tp_src(struct cls_rule *, ovs_be16); > > +void cls_rule_set_tp_src_masked(struct cls_rule *, > > + ovs_be16 port, ovs_be16 mask); > > void cls_rule_set_tp_dst(struct cls_rule *, ovs_be16); > > +void cls_rule_set_tp_dst_masked(struct cls_rule *, > > + ovs_be16 port, ovs_be16 mask); > > void cls_rule_set_nw_proto(struct cls_rule *, uint8_t); > > void cls_rule_set_nw_src(struct cls_rule *, ovs_be32); > > void cls_rule_set_nw_src_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 > > mask); > > diff --git a/lib/flow.c b/lib/flow.c > > index dc2bb1c..9f83b2c 100644 > > --- a/lib/flow.c > > +++ b/lib/flow.c > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks. > > + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks. > > * > > * Licensed under the Apache License, Version 2.0 (the "License"); > > * you may not use this file except in compliance with the License. > > @@ -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 == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > for (i = 0; i < FLOW_N_REGS; i++) { > > flow->regs[i] &= wildcards->reg_masks[i]; > > @@ -459,12 +459,8 @@ flow_zero_wildcards(struct flow *flow, const struct > > flow_wildcards *wildcards) > > if (wc & FWW_DL_TYPE) { > > flow->dl_type = htons(0); > > } > > - if (wc & FWW_TP_SRC) { > > - flow->tp_src = htons(0); > > - } > > - if (wc & FWW_TP_DST) { > > - flow->tp_dst = htons(0); > > - } > > + flow->tp_src &= wildcards->tp_src_mask; > > + flow->tp_dst &= wildcards->tp_dst_mask; > > if (wc & FWW_DL_SRC) { > > memset(flow->dl_src, 0, sizeof flow->dl_src); > > } > > @@ -598,7 +594,7 @@ flow_print(FILE *stream, const struct flow *flow) > > void > > flow_wildcards_init_catchall(struct flow_wildcards *wc) > > { > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > wc->wildcards = FWW_ALL; > > wc->tun_id_mask = htonll(0); > > @@ -609,6 +605,8 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc) > > memset(wc->reg_masks, 0, sizeof wc->reg_masks); > > wc->vlan_tci_mask = htons(0); > > wc->nw_frag_mask = 0; > > + wc->tp_src_mask = htons(0); > > + wc->tp_dst_mask = htons(0); > > memset(wc->zeros, 0, sizeof wc->zeros); > > } > > > > @@ -617,7 +615,7 @@ flow_wildcards_init_catchall(struct flow_wildcards *wc) > > void > > flow_wildcards_init_exact(struct flow_wildcards *wc) > > { > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > wc->wildcards = 0; > > wc->tun_id_mask = htonll(UINT64_MAX); > > @@ -628,6 +626,8 @@ flow_wildcards_init_exact(struct flow_wildcards *wc) > > memset(wc->reg_masks, 0xff, sizeof wc->reg_masks); > > wc->vlan_tci_mask = htons(UINT16_MAX); > > wc->nw_frag_mask = UINT8_MAX; > > + wc->tp_src_mask = htons(UINT16_MAX); > > + wc->tp_dst_mask = htons(UINT16_MAX); > > memset(wc->zeros, 0, sizeof wc->zeros); > > } > > > > @@ -638,12 +638,14 @@ flow_wildcards_is_exact(const struct flow_wildcards > > *wc) > > { > > int i; > > > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > if (wc->wildcards > > || wc->tun_id_mask != htonll(UINT64_MAX) > > || wc->nw_src_mask != htonl(UINT32_MAX) > > || wc->nw_dst_mask != htonl(UINT32_MAX) > > + || wc->tp_src_mask != htons(UINT16_MAX) > > + || wc->tp_dst_mask != htons(UINT16_MAX) > > || wc->vlan_tci_mask != htons(UINT16_MAX) > > || !ipv6_mask_is_exact(&wc->ipv6_src_mask) > > || !ipv6_mask_is_exact(&wc->ipv6_dst_mask) > > @@ -667,12 +669,14 @@ flow_wildcards_is_catchall(const struct > > flow_wildcards *wc) > > { > > int i; > > > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > if (wc->wildcards != FWW_ALL > > || wc->tun_id_mask != htonll(0) > > || wc->nw_src_mask != htonl(0) > > || wc->nw_dst_mask != htonl(0) > > + || wc->tp_src_mask != htons(0) > > + || wc->tp_dst_mask != htons(0) > > || wc->vlan_tci_mask != htons(0) > > || !ipv6_mask_is_any(&wc->ipv6_src_mask) > > || !ipv6_mask_is_any(&wc->ipv6_dst_mask) > > @@ -699,7 +703,7 @@ flow_wildcards_combine(struct flow_wildcards *dst, > > { > > int i; > > > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > dst->wildcards = src1->wildcards | src2->wildcards; > > dst->tun_id_mask = src1->tun_id_mask & src2->tun_id_mask; > > @@ -713,6 +717,8 @@ flow_wildcards_combine(struct flow_wildcards *dst, > > dst->reg_masks[i] = src1->reg_masks[i] & src2->reg_masks[i]; > > } > > dst->vlan_tci_mask = src1->vlan_tci_mask & src2->vlan_tci_mask; > > + dst->tp_src_mask = src1->tp_src_mask & src2->tp_src_mask; > > + dst->tp_dst_mask = src1->tp_dst_mask & src2->tp_dst_mask; > > } > > > > /* Returns a hash of the wildcards in 'wc'. */ > > @@ -734,7 +740,7 @@ flow_wildcards_equal(const struct flow_wildcards *a, > > { > > int i; > > > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > if (a->wildcards != b->wildcards > > || a->tun_id_mask != b->tun_id_mask > > @@ -742,7 +748,9 @@ flow_wildcards_equal(const struct flow_wildcards *a, > > || a->nw_dst_mask != b->nw_dst_mask > > || 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->ipv6_dst_mask, &b->ipv6_dst_mask) > > + || a->tp_src_mask != b->tp_src_mask > > + || a->tp_dst_mask != b->tp_dst_mask) { > > return false; > > } > > > > @@ -764,7 +772,7 @@ flow_wildcards_has_extra(const struct flow_wildcards *a, > > int i; > > struct in6_addr ipv6_masked; > > > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > for (i = 0; i < FLOW_N_REGS; i++) { > > if ((a->reg_masks[i] & b->reg_masks[i]) != b->reg_masks[i]) { > > @@ -786,7 +794,9 @@ flow_wildcards_has_extra(const struct flow_wildcards *a, > > || (a->tun_id_mask & b->tun_id_mask) != b->tun_id_mask > > || (a->nw_src_mask & b->nw_src_mask) != b->nw_src_mask > > || (a->nw_dst_mask & b->nw_dst_mask) != b->nw_dst_mask > > - || (a->vlan_tci_mask & b->vlan_tci_mask) != b->vlan_tci_mask); > > + || (a->vlan_tci_mask & b->vlan_tci_mask) != b->vlan_tci_mask > > + || (a->tp_src_mask & b->tp_src_mask) != b->tp_src_mask > > + || (a->tp_dst_mask & b->tp_dst_mask) != b->tp_dst_mask); > > } > > > > /* Sets the wildcard mask for register 'idx' in 'wc' to 'mask'. > > diff --git a/lib/flow.h b/lib/flow.h > > index 44eb977..7b001a6 100644 > > --- a/lib/flow.h > > +++ b/lib/flow.h > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks. > > + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks. > > * > > * Licensed under the Apache License, Version 2.0 (the "License"); > > * you may not use this file except in compliance with the License. > > @@ -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 7 > > +#define FLOW_WC_SEQ 8 > > > > #define FLOW_N_REGS 5 > > 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 == 130 && FLOW_WC_SEQ == 7); > > +BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 130 && FLOW_WC_SEQ == 8); > > > > void flow_extract(struct ofpbuf *, uint32_t priority, ovs_be64 tun_id, > > uint16_t in_port, struct flow *); > > @@ -152,22 +152,20 @@ typedef unsigned int OVS_BITWISE flow_wildcards_t; > > /* excluding the multicast > > bit */ > > #define FWW_DL_TYPE ((OVS_FORCE flow_wildcards_t) (1 << 4)) > > #define FWW_NW_PROTO ((OVS_FORCE flow_wildcards_t) (1 << 5)) > > -#define FWW_TP_SRC ((OVS_FORCE flow_wildcards_t) (1 << 6)) > > -#define FWW_TP_DST ((OVS_FORCE flow_wildcards_t) (1 << 7)) > > /* No corresponding OFPFW_* bits. */ > > #define FWW_ETH_MCAST ((OVS_FORCE flow_wildcards_t) (1 << 1)) > > /* multicast bit > > only */ > > +#define FWW_NW_DSCP ((OVS_FORCE flow_wildcards_t) (1 << 6)) > > +#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_NW_DSCP ((OVS_FORCE flow_wildcards_t) (1 << 13)) > > -#define FWW_NW_ECN ((OVS_FORCE flow_wildcards_t) (1 << 14)) > > -#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 15)) - 1)) > > +#define FWW_ALL ((OVS_FORCE flow_wildcards_t) (((1 << 13)) - 1)) > > > > /* Remember to update FLOW_WC_SEQ when adding or removing FWW_*. */ > > -BUILD_ASSERT_DECL(FWW_ALL == ((1 << 15) - 1) && FLOW_WC_SEQ == 7); > > +BUILD_ASSERT_DECL(FWW_ALL == ((1 << 13) - 1) && FLOW_WC_SEQ == 8); > > > > /* Information on wildcards for a flow, as a supplement to "struct flow". > > * > > @@ -182,12 +180,14 @@ struct flow_wildcards { > > 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. */ > > 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. */ > > uint8_t nw_frag_mask; /* 1-bit in each significant nw_frag bit. */ > > - uint8_t zeros[5]; /* Padding field set to zero. */ > > + uint8_t zeros[1]; /* Padding field set to zero. */ > > }; > > > > /* Remember to update FLOW_WC_SEQ when updating struct flow_wildcards. */ > > -BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 80 && FLOW_WC_SEQ == 7); > > +BUILD_ASSERT_DECL(sizeof(struct flow_wildcards) == 80 && FLOW_WC_SEQ == 8); > > > > void flow_wildcards_init_catchall(struct flow_wildcards *); > > void flow_wildcards_init_exact(struct flow_wildcards *); > > diff --git a/lib/meta-flow.c b/lib/meta-flow.c > > index 41cbf49..8d649e4 100644 > > --- a/lib/meta-flow.c > > +++ b/lib/meta-flow.c > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright (c) 2011 Nicira Networks. > > + * Copyright (c) 2011, 2012 Nicira Networks. > > * > > * Licensed under the Apache License, Version 2.0 (the "License"); > > * you may not use this file except in compliance with the License. > > @@ -286,7 +286,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { > > { > > MFF_TCP_SRC, "tcp_src", "tp_src", > > MF_FIELD_SIZES(be16), > > - MFM_NONE, FWW_TP_SRC, > > + MFM_FULLY, 0, > > MFS_DECIMAL, > > MFP_TCP, > > true, > > @@ -294,7 +294,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { > > }, { > > MFF_TCP_DST, "tcp_dst", "tp_dst", > > MF_FIELD_SIZES(be16), > > - MFM_NONE, FWW_TP_DST, > > + MFM_FULLY, 0, > > MFS_DECIMAL, > > MFP_TCP, > > true, > > @@ -304,7 +304,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { > > { > > MFF_UDP_SRC, "udp_src", NULL, > > MF_FIELD_SIZES(be16), > > - MFM_NONE, FWW_TP_SRC, > > + MFM_FULLY, 0, > > MFS_DECIMAL, > > MFP_UDP, > > true, > > @@ -312,7 +312,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { > > }, { > > MFF_UDP_DST, "udp_dst", NULL, > > MF_FIELD_SIZES(be16), > > - MFM_NONE, FWW_TP_DST, > > + MFM_FULLY, 0, > > MFS_DECIMAL, > > MFP_UDP, > > true, > > @@ -322,7 +322,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { > > { > > MFF_ICMPV4_TYPE, "icmp_type", NULL, > > MF_FIELD_SIZES(u8), > > - MFM_NONE, FWW_TP_SRC, > > + MFM_NONE, 0, > > MFS_DECIMAL, > > MFP_ICMPV4, > > false, > > @@ -330,7 +330,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { > > }, { > > MFF_ICMPV4_CODE, "icmp_code", NULL, > > MF_FIELD_SIZES(u8), > > - MFM_NONE, FWW_TP_DST, > > + MFM_NONE, 0, > > MFS_DECIMAL, > > MFP_ICMPV4, > > false, > > @@ -340,7 +340,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { > > { > > MFF_ICMPV6_TYPE, "icmpv6_type", NULL, > > MF_FIELD_SIZES(u8), > > - MFM_NONE, FWW_TP_SRC, > > + MFM_NONE, 0, > > MFS_DECIMAL, > > MFP_ICMPV6, > > false, > > @@ -348,7 +348,7 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { > > }, { > > MFF_ICMPV6_CODE, "icmpv6_code", NULL, > > MF_FIELD_SIZES(u8), > > - MFM_NONE, FWW_TP_DST, > > + MFM_NONE, 0, > > MFS_DECIMAL, > > MFP_ICMPV6, > > false, > > @@ -501,14 +501,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_TCP_SRC: > > - case MFF_TCP_DST: > > - case MFF_UDP_SRC: > > - case MFF_UDP_DST: > > - case MFF_ICMPV4_TYPE: > > - case MFF_ICMPV4_CODE: > > - case MFF_ICMPV6_TYPE: > > - case MFF_ICMPV6_CODE: > > case MFF_ND_TARGET: > > case MFF_ND_SLL: > > case MFF_ND_TLL: > > @@ -567,6 +559,17 @@ mf_is_all_wild(const struct mf_field *mf, const struct > > flow_wildcards *wc) > > case MFF_ARP_TPA: > > return !wc->nw_dst_mask; > > > > + case MFF_TCP_SRC: > > + case MFF_UDP_SRC: > > + case MFF_ICMPV4_TYPE: > > + case MFF_ICMPV6_TYPE: > > + return !wc->tp_src_mask; > > + case MFF_TCP_DST: > > + case MFF_UDP_DST: > > + case MFF_ICMPV4_CODE: > > + case MFF_ICMPV6_CODE: > > + return !wc->tp_dst_mask; > > + > > case MFF_N_IDS: > > default: > > NOT_REACHED(); > > @@ -595,14 +598,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_TCP_SRC: > > - case MFF_TCP_DST: > > - case MFF_UDP_SRC: > > - case MFF_UDP_DST: > > - case MFF_ICMPV4_TYPE: > > - case MFF_ICMPV4_CODE: > > - case MFF_ICMPV6_TYPE: > > - case MFF_ICMPV6_CODE: > > case MFF_ND_TARGET: > > case MFF_ND_SLL: > > case MFF_ND_TLL: > > @@ -675,6 +670,24 @@ mf_get_mask(const struct mf_field *mf, const struct > > flow_wildcards *wc, > > mask->be32 = wc->nw_dst_mask; > > break; > > > > + case MFF_TCP_SRC: > > + case MFF_UDP_SRC: > > + mask->be16 = wc->tp_src_mask; > > + break; > > + case MFF_TCP_DST: > > + case MFF_UDP_DST: > > + mask->be16 = wc->tp_dst_mask; > > + break; > > + > > + case MFF_ICMPV4_TYPE: > > + case MFF_ICMPV6_TYPE: > > + mask->u8 = ntohs(wc->tp_src_mask); > > + break; > > + case MFF_ICMPV4_CODE: > > + case MFF_ICMPV6_CODE: > > + mask->u8 = ntohs(wc->tp_dst_mask); > > + break; > > + > > case MFF_N_IDS: > > default: > > NOT_REACHED(); > > @@ -1477,7 +1490,7 @@ mf_set_wild(const struct mf_field *mf, struct > > cls_rule *rule) > > case MFF_UDP_SRC: > > case MFF_ICMPV4_TYPE: > > case MFF_ICMPV6_TYPE: > > - rule->wc.wildcards |= FWW_TP_SRC; > > + rule->wc.tp_src_mask = htons(0); > > rule->flow.tp_src = htons(0); > > break; > > > > @@ -1485,7 +1498,7 @@ mf_set_wild(const struct mf_field *mf, struct > > cls_rule *rule) > > case MFF_UDP_DST: > > case MFF_ICMPV4_CODE: > > case MFF_ICMPV6_CODE: > > - rule->wc.wildcards |= FWW_TP_DST; > > + rule->wc.tp_dst_mask = htons(0); > > rule->flow.tp_dst = htons(0); > > break; > > > > @@ -1538,10 +1551,6 @@ mf_set(const struct mf_field *mf, > > case MFF_ARP_OP: > > case MFF_ARP_SHA: > > case MFF_ARP_THA: > > - case MFF_TCP_SRC: > > - case MFF_TCP_DST: > > - case MFF_UDP_SRC: > > - case MFF_UDP_DST: > > case MFF_ICMPV4_TYPE: > > case MFF_ICMPV4_CODE: > > case MFF_ICMPV6_TYPE: > > @@ -1615,6 +1624,16 @@ mf_set(const struct mf_field *mf, > > cls_rule_set_nw_dst_masked(rule, value->be32, mask->be32); > > break; > > > > + case MFF_TCP_SRC: > > + case MFF_UDP_SRC: > > + cls_rule_set_tp_src_masked(rule, value->be16, mask->be16); > > + break; > > + > > + case MFF_TCP_DST: > > + case MFF_UDP_DST: > > + cls_rule_set_tp_dst_masked(rule, value->be16, mask->be16); > > + break; > > + > > case MFF_N_IDS: > > default: > > NOT_REACHED(); > > diff --git a/lib/nx-match.c b/lib/nx-match.c > > index f42bb9a..a43ed6a 100644 > > --- a/lib/nx-match.c > > +++ b/lib/nx-match.c > > @@ -433,24 +433,16 @@ nxm_put_ip(struct ofpbuf *b, const struct cls_rule > > *cr, > > } > > > > if (flow->nw_proto == IPPROTO_TCP) { > > - if (!(wc & FWW_TP_SRC)) { > > - nxm_put_16(b, NXM_OF_TCP_SRC, flow->tp_src); > > - } > > - if (!(wc & FWW_TP_DST)) { > > - nxm_put_16(b, NXM_OF_TCP_DST, flow->tp_dst); > > - } > > + nxm_put_16m(b, NXM_OF_TCP_SRC, flow->tp_src, cr->wc.tp_src_mask); > > + nxm_put_16m(b, NXM_OF_TCP_DST, flow->tp_dst, cr->wc.tp_dst_mask); > > } else if (flow->nw_proto == IPPROTO_UDP) { > > - if (!(wc & FWW_TP_SRC)) { > > - nxm_put_16(b, NXM_OF_UDP_SRC, flow->tp_src); > > - } > > - if (!(wc & FWW_TP_DST)) { > > - nxm_put_16(b, NXM_OF_UDP_DST, flow->tp_dst); > > - } > > + nxm_put_16m(b, NXM_OF_UDP_SRC, flow->tp_src, cr->wc.tp_src_mask); > > + nxm_put_16m(b, NXM_OF_UDP_DST, flow->tp_dst, cr->wc.tp_dst_mask); > > } else if (flow->nw_proto == icmp_proto) { > > - if (!(wc & FWW_TP_SRC)) { > > + if (cr->wc.tp_src_mask) { > > nxm_put_8(b, icmp_type, ntohs(flow->tp_src)); > > } > > - if (!(wc & FWW_TP_DST)) { > > + if (cr->wc.tp_dst_mask) { > > nxm_put_8(b, icmp_code, ntohs(flow->tp_dst)); > > } > > } > > @@ -478,7 +470,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule > > *cr, > > int match_len; > > int i; > > > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > /* Metadata. */ > > if (!(wc & FWW_IN_PORT)) { > > diff --git a/lib/ofp-util.c b/lib/ofp-util.c > > index 6fe1611..876abaf 100644 > > --- a/lib/ofp-util.c > > +++ b/lib/ofp-util.c > > @@ -77,9 +77,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask) > > WC_INVARIANT_BIT(DL_SRC) \ > > WC_INVARIANT_BIT(DL_DST) \ > > WC_INVARIANT_BIT(DL_TYPE) \ > > - WC_INVARIANT_BIT(NW_PROTO) \ > > - WC_INVARIANT_BIT(TP_SRC) \ > > - WC_INVARIANT_BIT(TP_DST) > > + WC_INVARIANT_BIT(NW_PROTO) > > > > /* Verify that all of the invariant bits (as defined on WC_INVARIANT_LIST) > > * actually have the same names and values. */ > > @@ -101,7 +99,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 == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > /* Initialize most of rule->wc. */ > > flow_wildcards_init_catchall(wc); > > @@ -120,6 +118,13 @@ ofputil_wildcard_from_openflow(uint32_t ofpfw, struct > > flow_wildcards *wc) > > wc->nw_src_mask = ofputil_wcbits_to_netmask(ofpfw >> > > OFPFW_NW_SRC_SHIFT); > > wc->nw_dst_mask = ofputil_wcbits_to_netmask(ofpfw >> > > OFPFW_NW_DST_SHIFT); > > > > + if (!(ofpfw & OFPFW_TP_SRC)) { > > + wc->tp_src_mask = htons(UINT16_MAX); > > + } > > + if (!(ofpfw & OFPFW_TP_DST)) { > > + wc->tp_dst_mask = htons(UINT16_MAX); > > + } > > + > > if (ofpfw & OFPFW_DL_DST) { > > /* OpenFlow 1.0 OFPFW_DL_DST covers the whole Ethernet destination, > > but > > * Open vSwitch breaks the Ethernet destination into bits as > > FWW_DL_DST > > @@ -199,6 +204,12 @@ ofputil_cls_rule_to_match(const struct cls_rule *rule, > > struct ofp_match *match) > > if (wc->wildcards & FWW_NW_DSCP) { > > ofpfw |= OFPFW_NW_TOS; > > } > > + if (!wc->tp_src_mask) { > > + ofpfw |= OFPFW_TP_SRC; > > + } > > + if (!wc->tp_dst_mask) { > > + ofpfw |= OFPFW_TP_DST; > > + } > > > > /* Translate VLANs. */ > > match->dl_vlan = htons(0); > > @@ -904,7 +915,7 @@ ofputil_min_flow_format(const struct cls_rule *rule) > > { > > const struct flow_wildcards *wc = &rule->wc; > > > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 7); > > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 8); > > > > /* Only NXM supports separately wildcards the Ethernet multicast bit. */ > > if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) { > > @@ -952,6 +963,12 @@ ofputil_min_flow_format(const struct cls_rule *rule) > > return NXFF_NXM; > > } > > > > + /* Only NXM supports bitwise matching on transport port. */ > > + if ((wc->tp_src_mask && wc->tp_src_mask != htons(UINT16_MAX)) || > > + (wc->tp_dst_mask && wc->tp_dst_mask != htons(UINT16_MAX))) { > > + return NXFF_NXM; > > + } > > + > > /* Other formats can express this rule. */ > > return NXFF_OPENFLOW10; > > } > > @@ -2733,7 +2750,7 @@ ofputil_normalize_rule(struct cls_rule *rule, enum > > nx_flow_format flow_format) > > wc.nw_src_mask = wc.nw_dst_mask = htonl(0); > > } > > if (!(may_match & MAY_TP_ADDR)) { > > - wc.wildcards |= FWW_TP_SRC | FWW_TP_DST; > > + wc.tp_src_mask = wc.tp_dst_mask = htons(0); > > } > > if (!(may_match & MAY_NW_PROTO)) { > > wc.wildcards |= FWW_NW_PROTO; > > diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at > > index 0b58b3d..4869dd7 100644 > > --- a/tests/ovs-ofctl.at > > +++ b/tests/ovs-ofctl.at > > @@ -10,7 +10,7 @@ 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 > > 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 > > +tcp,tp_src=0x1230/0xfff0,tun_id=0x1234,cookie=0x5678,actions=flood > > actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel:0x123456789 > > actions=multipath(eth_src, 50, hrw, 12, 0, > > NXM_NX_REG0[0..3]),multipath(symmetric_l4, 1024, iter_hash, 5000, 5050, > > NXM_NX_REG0[0..12]) > > table=1,actions=drop > > @@ -40,7 +40,7 @@ OFPT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 > > actions=pop_queue,output:1 > > OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 > > actions=CONTROLLER:65535 > > OFPT_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_SET_FLOW_FORMAT: format=nxm > > -NXT_FLOW_MOD: ADD tun_id=0x1234 cookie:0x5678 actions=FLOOD > > +NXT_FLOW_MOD: ADD tcp,tun_id=0x1234,tp_src=0x1230/0xfff0 cookie:0x5678 > > actions=FLOOD > > NXT_FLOW_MOD: ADD > > actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel64:0x123456789 > > NXT_FLOW_MOD: ADD > > actions=multipath(eth_src,50,hrw,12,0,NXM_NX_REG0[0..3]),multipath(symmetric_l4,1024,iter_hash,5000,5050,NXM_NX_REG0[0..12]) > > NXT_FLOW_MOD_TABLE_ID: enable > > @@ -243,18 +243,22 @@ NXM_OF_ETH_TYPE(0806) > > NXM_OF_IP_DST_W(C0D80000/FFFF0000) > > > > # TCP source port > > NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(06) NXM_OF_TCP_SRC(4231) > > +NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(06) NXM_OF_TCP_SRC_W(5050/F0F0) > > NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(07) NXM_OF_TCP_SRC(4231) > > > > # TCP destination port > > NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(06) NXM_OF_TCP_DST(4231) > > +NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(06) NXM_OF_TCP_DST_W(FDE0/FFF0) > > NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(07) NXM_OF_TCP_DST(4231) > > > > # UDP source port > > NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(11) NXM_OF_UDP_SRC(8732) > > +NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(11) NXM_OF_UDP_SRC_W(0132/01FF) > > NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(06) NXM_OF_UDP_SRC(7823) > > > > # UDP destination port > > NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(11) NXM_OF_UDP_DST(1782) > > +NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(11) NXM_OF_UDP_DST_W(5005/F00F) > > NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(02) NXM_OF_UDP_DST(1293) > > > > # ICMP type > > @@ -436,18 +440,22 @@ nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ > > > > # TCP source port > > NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC(4231) > > +NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC_W(5050/f0f0) > > nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ > > > > # TCP destination port > > NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_DST(4231) > > +NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_DST_W(fde0/fff0) > > nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ > > > > # UDP source port > > NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_SRC(8732) > > +NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_SRC_W(0132/01ff) > > nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ > > > > # UDP destination port > > NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_DST(1782) > > +NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(11), NXM_OF_UDP_DST_W(5005/f00f) > > nx_pull_match() returned error NXBRC_NXM_BAD_PREREQ > > > > # ICMP type > > diff --git a/tests/test-classifier.c b/tests/test-classifier.c > > index 8dfe016..1a07790 100644 > > --- a/tests/test-classifier.c > > +++ b/tests/test-classifier.c > > @@ -1,5 +1,5 @@ > > /* > > - * Copyright (c) 2009, 2010, 2011 Nicira Networks. > > + * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks. > > * > > * Licensed under the Apache License, Version 2.0 (the "License"); > > * you may not use this file except in compliance with the License. > > @@ -50,8 +50,8 @@ > > CLS_FIELD(FWW_IN_PORT, in_port, IN_PORT) \ > > CLS_FIELD(0, vlan_tci, VLAN_TCI) \ > > CLS_FIELD(FWW_DL_TYPE, dl_type, DL_TYPE) \ > > - CLS_FIELD(FWW_TP_SRC, tp_src, TP_SRC) \ > > - CLS_FIELD(FWW_TP_DST, tp_dst, TP_DST) \ > > + CLS_FIELD(0, tp_src, TP_SRC) \ > > + CLS_FIELD(0, tp_dst, TP_DST) \ > > CLS_FIELD(FWW_DL_SRC, dl_src, DL_SRC) \ > > CLS_FIELD(FWW_DL_DST | FWW_ETH_MCAST, dl_dst, DL_DST) \ > > CLS_FIELD(FWW_NW_PROTO, nw_proto, NW_PROTO) \ > > @@ -198,6 +198,10 @@ match(const struct cls_rule *wild, const struct flow > > *fixed) > > eq = !((fixed->nw_src ^ wild->flow.nw_src) & > > wild->wc.nw_src_mask); > > } else if (f_idx == CLS_F_IDX_NW_DST) { > > eq = !((fixed->nw_dst ^ wild->flow.nw_dst) & > > wild->wc.nw_dst_mask); > > + } else if (f_idx == CLS_F_IDX_TP_SRC) { > > + eq = !((fixed->tp_src ^ wild->flow.tp_src) & > > wild->wc.tp_src_mask); > > + } else if (f_idx == CLS_F_IDX_TP_DST) { > > + eq = !((fixed->tp_dst ^ wild->flow.tp_dst) & > > wild->wc.tp_dst_mask); > > } else if (f_idx == CLS_F_IDX_VLAN_TCI) { > > eq = !((fixed->vlan_tci ^ wild->flow.vlan_tci) > > & wild->wc.vlan_tci_mask); > > @@ -463,6 +467,10 @@ make_rule(int wc_fields, unsigned int priority, int > > value_pat) > > rule->cls_rule.wc.nw_src_mask = htonl(UINT32_MAX); > > } else if (f_idx == CLS_F_IDX_NW_DST) { > > rule->cls_rule.wc.nw_dst_mask = htonl(UINT32_MAX); > > + } else if (f_idx == CLS_F_IDX_TP_SRC) { > > + rule->cls_rule.wc.tp_src_mask = htons(UINT16_MAX); > > + } else if (f_idx == CLS_F_IDX_TP_DST) { > > + rule->cls_rule.wc.tp_dst_mask = htons(UINT16_MAX); > > } else if (f_idx == CLS_F_IDX_VLAN_TCI) { > > rule->cls_rule.wc.vlan_tci_mask = htons(UINT16_MAX); > > } else if (f_idx == CLS_F_IDX_TUN_ID) { > > diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in > > index e9e2e6f..e592953 100644 > > --- a/utilities/ovs-ofctl.8.in > > +++ b/utilities/ovs-ofctl.8.in > > @@ -443,13 +443,75 @@ above). > > .IQ \fBtp_dst=\fIport\fR > > When \fBdl_type\fR and \fBnw_proto\fR specify TCP or UDP, \fBtp_src\fR > > and \fBtp_dst\fR match the UDP or TCP source or destination port > > -\fIport\fR, respectively. which is specified as a decimal number > > +\fIport\fR, respectively, which is specified as a decimal number > > between 0 and 65535, inclusive (e.g. 80 to match packets originating > > from a HTTP server). > > .IP > > When \fBdl_type\fR and \fBnw_proto\fR take other values, the values of > > these settings are ignored (see \fBFlow Syntax\fR above). > > . > > +.IP \fBtp_src=\fIport\fB/\fImask\fR > > +.IQ \fBtp_dst=\fIport\fB/\fImask\fR > > +Bitwise match on TCP (or UDP) source or destination port, > > +respectively. The \fIport\fR and \fImask\fR are 16-bit numbers > > +written in decimal or in hexadecimal prefixed by \fB0x\fR. Each 1-bit > > +in \fImask\fR requires that the corresponding bit in \fIport\fR must > > +match. Each 0-bit in \fImask\fR causes the corresponding bit to be > > +ignored. > > +.IP > > +Bitwise matches on transport ports are rarely useful in isolation, but > > +a group of them can be used to reduce the number of flows required to > > +match on a range of transport ports. For example, suppose that the > > +goal is to match TCP source ports 1000 to 1999, inclusive. One way is > > +to insert 1001 flows, each of which matches on a single source port. > > +Another way is to look at the binary representations of 1000 and 1999, > > +as follows: > > +.br > > +.B "01111101000" > > +.br > > +.B "11111001111" > > +.br > > +and then to transform those into a series of bitwise matches that > > +accomplish the same results: > > +.br > > +.B "01111101xxx" > > +.br > > +.B "0111111xxxx" > > +.br > > +.B "10xxxxxxxxx" > > +.br > > +.B "110xxxxxxxx" > > +.br > > +.B "1110xxxxxxx" > > +.br > > +.B "11110xxxxxx" > > +.br > > +.B "1111100xxxx" > > +.br > > +which become the following when written in the syntax required by > > +\fBovs\-ofctl\fR: > > +.br > > +.B "tcp,tp_src=0x03e8/0xfff8" > > +.br > > +.B "tcp,tp_src=0x03f0/0xfff0" > > +.br > > +.B "tcp,tp_src=0x0400/0xfe00" > > +.br > > +.B "tcp,tp_src=0x0600/0xff00" > > +.br > > +.B "tcp,tp_src=0x0700/0xff80" > > +.br > > +.B "tcp,tp_src=0x0780/0xffc0" > > +.br > > +.B "tcp,tp_src=0x07c0/0xfff0" > > +.IP > > +Only Open vSwitch 1.6 and later supports bitwise matching on transport > > +ports. > > +.IP > > +Like the exact-match forms of \fBtp_src\fR and \fBtp_dst\fR described > > +above, the bitwise match forms apply only when When \fBdl_type\fR and > > +\fBnw_proto\fR specify TCP or UDP. > > +. > > .IP \fBicmp_type=\fItype\fR > > .IQ \fBicmp_code=\fIcode\fR > > When \fBdl_type\fR and \fBnw_proto\fR specify ICMP or ICMPv6, \fItype\fR > > -- > > 1.7.2.5 > > > > _______________________________________________ > > dev mailing list > > dev@openvswitch.org > > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev