Implement subnet mask matching in OpenFlow.
authorBen Pfaff <blp@nicira.com>
Thu, 7 Aug 2008 05:00:29 +0000 (22:00 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 18 Aug 2008 21:26:50 +0000 (14:26 -0700)
18 files changed:
datapath/datapath.c
datapath/flow.c
datapath/flow.h
datapath/hwtable_dummy/hwtable_dummy.c
datapath/table-hash.c
datapath/table-linear.c
datapath/table_t.c
include/openflow.h
include/packets.h
lib/ofp-print.c
lib/vconn.c
switch/datapath.c
switch/switch-flow.c
switch/switch-flow.h
switch/table-hash.c
switch/table-linear.c
utilities/dpctl.8
utilities/dpctl.c

index 6d9a8fe..5c3a84c 100644 (file)
@@ -1153,7 +1153,7 @@ static int flow_stats_dump_callback(struct sw_flow *flow, void *private)
        ofs->length          = htons(length);
        ofs->table_id        = s->table_idx;
        ofs->pad             = 0;
        ofs->length          = htons(length);
        ofs->table_id        = s->table_idx;
        ofs->pad             = 0;
-       ofs->match.wildcards = htons(flow->key.wildcards);
+       ofs->match.wildcards = htonl(flow->key.wildcards);
        ofs->match.in_port   = flow->key.in_port;
        memcpy(ofs->match.dl_src, flow->key.dl_src, ETH_ALEN);
        memcpy(ofs->match.dl_dst, flow->key.dl_dst, ETH_ALEN);
        ofs->match.in_port   = flow->key.in_port;
        memcpy(ofs->match.dl_src, flow->key.dl_src, ETH_ALEN);
        memcpy(ofs->match.dl_dst, flow->key.dl_dst, ETH_ALEN);
@@ -1162,7 +1162,7 @@ static int flow_stats_dump_callback(struct sw_flow *flow, void *private)
        ofs->match.nw_src    = flow->key.nw_src;
        ofs->match.nw_dst    = flow->key.nw_dst;
        ofs->match.nw_proto  = flow->key.nw_proto;
        ofs->match.nw_src    = flow->key.nw_src;
        ofs->match.nw_dst    = flow->key.nw_dst;
        ofs->match.nw_proto  = flow->key.nw_proto;
-       memset(ofs->match.pad, 0, sizeof ofs->match.pad);
+       ofs->match.pad       = 0;
        ofs->match.tp_src    = flow->key.tp_src;
        ofs->match.tp_dst    = flow->key.tp_dst;
        ofs->duration        = htonl((jiffies - flow->init_time) / HZ);
        ofs->match.tp_src    = flow->key.tp_src;
        ofs->match.tp_dst    = flow->key.tp_dst;
        ofs->duration        = htonl((jiffies - flow->init_time) / HZ);
index afd91bf..a2c96ab 100644 (file)
@@ -29,46 +29,65 @@ struct kmem_cache *flow_cache;
 /* Internal function used to compare fields in flow. */
 static inline
 int flow_fields_match(const struct sw_flow_key *a, const struct sw_flow_key *b,
 /* Internal function used to compare fields in flow. */
 static inline
 int flow_fields_match(const struct sw_flow_key *a, const struct sw_flow_key *b,
-               uint16_t w)
+                     uint32_t w, uint32_t src_mask, uint32_t dst_mask)
 {
        return ((w & OFPFW_IN_PORT || a->in_port == b->in_port)
                && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan)
                && (w & OFPFW_DL_SRC || !memcmp(a->dl_src, b->dl_src, ETH_ALEN))
                && (w & OFPFW_DL_DST || !memcmp(a->dl_dst, b->dl_dst, ETH_ALEN))
                && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type)
 {
        return ((w & OFPFW_IN_PORT || a->in_port == b->in_port)
                && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan)
                && (w & OFPFW_DL_SRC || !memcmp(a->dl_src, b->dl_src, ETH_ALEN))
                && (w & OFPFW_DL_DST || !memcmp(a->dl_dst, b->dl_dst, ETH_ALEN))
                && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type)
-               && (w & OFPFW_NW_SRC || a->nw_src == b->nw_src)
-               && (w & OFPFW_NW_DST || a->nw_dst == b->nw_dst)
+               && !((a->nw_src ^ b->nw_src) & src_mask)
+               && !((a->nw_dst ^ b->nw_dst) & dst_mask)
                && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto)
                && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src)
                && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst));
 }
 
 /* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal
                && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto)
                && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src)
                && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst));
 }
 
 /* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal
- * modulo wildcards, zero otherwise. */
-int flow_matches(const struct sw_flow_key *a, const struct sw_flow_key *b)
+ * modulo wildcards in 'b', zero otherwise. */
+int flow_matches_1wild(const struct sw_flow_key *a,
+                      const struct sw_flow_key *b)
 {
 {
-       return flow_fields_match(a, b, (a->wildcards | b->wildcards));
+       return flow_fields_match(a, b, b->wildcards,
+                                b->nw_src_mask, b->nw_dst_mask);
 }
 }
-EXPORT_SYMBOL(flow_matches);
+EXPORT_SYMBOL(flow_matches_1wild);
 
 
-/* Returns nonzero if 't' (the table entry's key) and 'd' (the key 
- * describing the deletion) match, that is, if their fields are 
+/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal
+ * modulo wildcards in 'a' or 'b', zero otherwise. */
+int flow_matches_2wild(const struct sw_flow_key *a,
+                      const struct sw_flow_key *b)
+{
+       return flow_fields_match(a, b,
+                                a->wildcards | b->wildcards,
+                                a->nw_src_mask & b->nw_src_mask,
+                                a->nw_dst_mask & b->nw_dst_mask);
+}
+EXPORT_SYMBOL(flow_matches_2wild);
+
+/* Returns nonzero if 't' (the table entry's key) and 'd' (the key
+ * describing the deletion) match, that is, if their fields are
  * equal modulo wildcards, zero otherwise.  If 'strict' is nonzero, the
  * wildcards must match in both 't_key' and 'd_key'.  Note that the
  * table's wildcards are ignored unless 'strict' is set. */
 int flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict)
 {
  * equal modulo wildcards, zero otherwise.  If 'strict' is nonzero, the
  * wildcards must match in both 't_key' and 'd_key'.  Note that the
  * table's wildcards are ignored unless 'strict' is set. */
 int flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict)
 {
-       if (strict && (t->wildcards != d->wildcards))
+       if (strict && d->wildcards != t->wildcards)
                return 0;
                return 0;
-
-       return flow_fields_match(t, d, d->wildcards);
+       return flow_matches_1wild(t, d);
 }
 EXPORT_SYMBOL(flow_del_matches);
 
 }
 EXPORT_SYMBOL(flow_del_matches);
 
+static uint32_t make_nw_mask(int n_wild_bits)
+{
+       n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1;
+       return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0;
+}
+
 void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
 {
 void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
 {
-       to->wildcards = ntohs(from->wildcards) & OFPFW_ALL;
-       memset(to->pad, '\0', sizeof(to->pad));
+       to->wildcards = ntohl(from->wildcards) & OFPFW_ALL;
+       to->pad = 0;
        to->in_port = from->in_port;
        to->dl_vlan = from->dl_vlan;
        memcpy(to->dl_src, from->dl_src, ETH_ALEN);
        to->in_port = from->in_port;
        to->dl_vlan = from->dl_vlan;
        memcpy(to->dl_src, from->dl_src, ETH_ALEN);
@@ -79,7 +98,7 @@ void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
        to->tp_src = to->tp_dst = 0;
 
 #define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST)
        to->tp_src = to->tp_dst = 0;
 
 #define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST)
-#define OFPFW_NW (OFPFW_NW_SRC | OFPFW_NW_DST | OFPFW_NW_PROTO)
+#define OFPFW_NW (OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_NW_PROTO)
        if (to->wildcards & OFPFW_DL_TYPE) {
                /* Can't sensibly match on network or transport headers if the
                 * data link type is unknown. */
        if (to->wildcards & OFPFW_DL_TYPE) {
                /* Can't sensibly match on network or transport headers if the
                 * data link type is unknown. */
@@ -109,11 +128,15 @@ void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
                 * instead of falling into table-linear. */
                to->wildcards &= ~(OFPFW_NW | OFPFW_TP);
        }
                 * instead of falling into table-linear. */
                to->wildcards &= ~(OFPFW_NW | OFPFW_TP);
        }
+
+       /* We set these late because code above adjusts to->wildcards. */
+       to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT);
+       to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT);
 }
 
 void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from)
 {
 }
 
 void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from)
 {
-       to->wildcards = htons(from->wildcards);
+       to->wildcards = htonl(from->wildcards);
        to->in_port   = from->in_port;
        to->dl_vlan   = from->dl_vlan;
        memcpy(to->dl_src, from->dl_src, ETH_ALEN);
        to->in_port   = from->in_port;
        to->dl_vlan   = from->dl_vlan;
        memcpy(to->dl_src, from->dl_src, ETH_ALEN);
@@ -124,7 +147,7 @@ void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from)
        to->nw_proto  = from->nw_proto;
        to->tp_src        = from->tp_src;
        to->tp_dst        = from->tp_dst;
        to->nw_proto  = from->nw_proto;
        to->tp_src        = from->tp_src;
        to->tp_dst        = from->tp_dst;
-       memset(to->pad, '\0', sizeof(to->pad));
+       to->pad           = 0;
 }
 
 int flow_timeout(struct sw_flow *flow)
 }
 
 int flow_timeout(struct sw_flow *flow)
@@ -187,7 +210,7 @@ EXPORT_SYMBOL(flow_deferred_free);
 /* Prints a representation of 'key' to the kernel log. */
 void print_flow(const struct sw_flow_key *key)
 {
 /* Prints a representation of 'key' to the kernel log. */
 void print_flow(const struct sw_flow_key *key)
 {
-       printk("wild%04x port%04x:vlan%04x mac%02x:%02x:%02x:%02x:%02x:%02x"
+       printk("wild%08x port%04x:vlan%04x mac%02x:%02x:%02x:%02x:%02x:%02x"
                        "->%02x:%02x:%02x:%02x:%02x:%02x "
                        "proto%04x ip%u.%u.%u.%u->%u.%u.%u.%u port%d->%d\n",
                        key->wildcards, ntohs(key->in_port), ntohs(key->dl_vlan),
                        "->%02x:%02x:%02x:%02x:%02x:%02x "
                        "proto%04x ip%u.%u.%u.%u->%u.%u.%u.%u port%d->%d\n",
                        key->wildcards, ntohs(key->in_port), ntohs(key->dl_vlan),
@@ -236,8 +259,10 @@ int flow_extract(struct sk_buff *skb, uint16_t in_port,
        int retval = 0;
 
        key->in_port = htons(in_port);
        int retval = 0;
 
        key->in_port = htons(in_port);
+       key->pad = 0;
        key->wildcards = 0;
        key->wildcards = 0;
-       memset(key->pad, '\0', sizeof(key->pad));
+       key->nw_src_mask = 0;
+       key->nw_dst_mask = 0;
 
        /* This code doesn't check that skb->len is long enough to contain the
         * MAC or network header.  With a 46-byte minimum length frame this
 
        /* This code doesn't check that skb->len is long enough to contain the
         * MAC or network header.  With a 46-byte minimum length frame this
index 3438d96..00445f4 100644 (file)
@@ -23,18 +23,20 @@ struct ofp_flow_mod;
    inter-flow variability, so that failing bytewise comparisons with memcmp
    terminate as quickly as possible on average. */
 struct sw_flow_key {
    inter-flow variability, so that failing bytewise comparisons with memcmp
    terminate as quickly as possible on average. */
 struct sw_flow_key {
+       uint32_t wildcards;         /* Wildcard fields (host byte order). */
        uint32_t nw_src;                /* IP source address. */
        uint32_t nw_src;                /* IP source address. */
+       uint32_t nw_src_mask;   /* 1-bit in each significant nw_src bit. */
        uint32_t nw_dst;                /* IP destination address. */
        uint32_t nw_dst;                /* IP destination address. */
+       uint32_t nw_dst_mask;       /* 1-bit in each significant nw_dst bit. */
        uint16_t in_port;           /* Input switch port */
        uint16_t dl_vlan;           /* Input VLAN. */
        uint16_t dl_type;           /* Ethernet frame type. */
        uint16_t tp_src;        /* TCP/UDP source port. */
        uint16_t tp_dst;        /* TCP/UDP destination port. */
        uint16_t in_port;           /* Input switch port */
        uint16_t dl_vlan;           /* Input VLAN. */
        uint16_t dl_type;           /* Ethernet frame type. */
        uint16_t tp_src;        /* TCP/UDP source port. */
        uint16_t tp_dst;        /* TCP/UDP destination port. */
-       uint16_t wildcards;         /* Wildcard fields (host byte order). */
        uint8_t dl_src[ETH_ALEN];           /* Ethernet source address. */
        uint8_t dl_dst[ETH_ALEN];           /* Ethernet destination address. */
        uint8_t nw_proto;               /* IP protocol. */
        uint8_t dl_src[ETH_ALEN];           /* Ethernet source address. */
        uint8_t dl_dst[ETH_ALEN];           /* Ethernet destination address. */
        uint8_t nw_proto;               /* IP protocol. */
-       uint8_t pad[3];             /* NB: Pad to make 32-bit aligned */
+       uint8_t pad;                /* NB: Pad to make 32-bit aligned */
 };
 
 /* We need to manually make sure that the structure is 32-bit aligned,
 };
 
 /* We need to manually make sure that the structure is 32-bit aligned,
@@ -43,7 +45,7 @@ struct sw_flow_key {
  */
 static inline void check_key_align(void)
 {
  */
 static inline void check_key_align(void)
 {
-       BUILD_BUG_ON(sizeof(struct sw_flow_key) != 36); 
+       BUILD_BUG_ON(sizeof(struct sw_flow_key) != 44); 
 }
 
 /* Locking:
 }
 
 /* Locking:
@@ -79,7 +81,8 @@ struct sw_flow {
        struct rcu_head rcu;
 };
 
        struct rcu_head rcu;
 };
 
-int flow_matches(const struct sw_flow_key *, const struct sw_flow_key *);
+int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *);
+int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *);
 int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *, 
                int);
 struct sw_flow *flow_alloc(int n_actions, gfp_t flags);
 int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *, 
                int);
 struct sw_flow *flow_alloc(int n_actions, gfp_t flags);
index d6699b9..6f21e1d 100644 (file)
@@ -73,7 +73,7 @@ static struct sw_flow *table_dummy_lookup(struct sw_table *swt,
        struct sw_table_dummy *td = (struct sw_table_dummy *) swt;
        struct sw_flow *flow;
        list_for_each_entry (flow, &td->flows, node) {
        struct sw_table_dummy *td = (struct sw_table_dummy *) swt;
        struct sw_flow *flow;
        list_for_each_entry (flow, &td->flows, node) {
-               if (flow_matches(&flow->key, key)) {
+               if (flow_matches_1wild(key, &flow->key)) {
                        return flow; 
                }
        }
                        return flow; 
                }
        }
@@ -196,7 +196,8 @@ static int table_dummy_iterate(struct sw_table *swt,
 
        start = ~position->private[0];
        list_for_each_entry (flow, &tl->iter_flows, iter_node) {
 
        start = ~position->private[0];
        list_for_each_entry (flow, &tl->iter_flows, iter_node) {
-               if (flow->serial <= start && flow_matches(key, &flow->key)) {
+               if (flow->serial <= start && flow_matches_2wild(key,
+                                                               &flow->key)) {
                        int error = callback(flow, private);
                        if (error) {
                                position->private[0] = ~flow->serial;
                        int error = callback(flow, private);
                        if (error) {
                                position->private[0] = ~flow->serial;
index 1c0c6e7..46acf80 100644 (file)
@@ -169,7 +169,7 @@ static int table_hash_iterate(struct sw_table *swt,
 
                for (i = position->private[0]; i <= th->bucket_mask; i++) {
                        struct sw_flow *flow = th->buckets[i];
 
                for (i = position->private[0]; i <= th->bucket_mask; i++) {
                        struct sw_flow *flow = th->buckets[i];
-                       if (flow && flow_matches(key, &flow->key)) {
+                       if (flow && flow_matches_1wild(&flow->key, key)) {
                                int error = callback(flow, private);
                                if (error) {
                                        position->private[0] = i;
                                int error = callback(flow, private);
                                if (error) {
                                        position->private[0] = i;
index d2d7e3c..e7c6e67 100644 (file)
@@ -28,7 +28,7 @@ static struct sw_flow *table_linear_lookup(struct sw_table *swt,
        struct sw_table_linear *tl = (struct sw_table_linear *) swt;
        struct sw_flow *flow;
        list_for_each_entry_rcu (flow, &tl->flows, node) {
        struct sw_table_linear *tl = (struct sw_table_linear *) swt;
        struct sw_flow *flow;
        list_for_each_entry_rcu (flow, &tl->flows, node) {
-               if (flow_matches(&flow->key, key))
+               if (flow_matches_1wild(key, &flow->key))
                        return flow;
        }
        return NULL;
                        return flow;
        }
        return NULL;
@@ -47,7 +47,7 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
        list_for_each_entry (f, &tl->flows, node) {
                if (f->priority == flow->priority
                                && f->key.wildcards == flow->key.wildcards
        list_for_each_entry (f, &tl->flows, node) {
                if (f->priority == flow->priority
                                && f->key.wildcards == flow->key.wildcards
-                               && flow_matches(&f->key, &flow->key)) {
+                               && flow_matches_2wild(&f->key, &flow->key)) {
                        flow->serial = f->serial;
                        list_replace_rcu(&f->node, &flow->node);
                        list_replace_rcu(&f->iter_node, &flow->iter_node);
                        flow->serial = f->serial;
                        list_replace_rcu(&f->node, &flow->node);
                        list_replace_rcu(&f->iter_node, &flow->iter_node);
@@ -140,7 +140,8 @@ static int table_linear_iterate(struct sw_table *swt,
 
        start = position->private[0];
        list_for_each_entry (flow, &tl->iter_flows, iter_node) {
 
        start = position->private[0];
        list_for_each_entry (flow, &tl->iter_flows, iter_node) {
-               if (flow->serial >= start && flow_matches(key, &flow->key)) {
+               if (flow->serial >= start
+                   && flow_matches_2wild(key, &flow->key)) {
                        int error = callback(flow, private);
                        if (error) {
                                position->private[0] = flow->serial;
                        int error = callback(flow, private);
                        if (error) {
                                position->private[0] = flow->serial;
index 3cc6a58..5f7cd1c 100644 (file)
@@ -43,7 +43,7 @@ static struct sw_flow *flow_zalloc(int n_actions, gfp_t flags)
 }
 
 static void
 }
 
 static void
-simple_insert_delete(struct sw_table *swt, uint16_t wildcards)
+simple_insert_delete(struct sw_table *swt, uint32_t wildcards)
 {
        struct sw_flow *a_flow = flow_zalloc(0, GFP_KERNEL);
        struct sw_flow *b_flow = flow_zalloc(0, GFP_KERNEL);
 {
        struct sw_flow *a_flow = flow_zalloc(0, GFP_KERNEL);
        struct sw_flow *b_flow = flow_zalloc(0, GFP_KERNEL);
@@ -81,7 +81,7 @@ simple_insert_delete(struct sw_table *swt, uint16_t wildcards)
 }
 
 static void
 }
 
 static void
-multiple_insert_destroy(struct sw_table *swt, int inserts, uint16_t wildcards,
+multiple_insert_destroy(struct sw_table *swt, int inserts, uint32_t wildcards,
                        int min_collisions, int max_collisions)
 {
        int i;
                        int min_collisions, int max_collisions)
 {
        int i;
@@ -124,7 +124,7 @@ multiple_insert_destroy(struct sw_table *swt, int inserts, uint16_t wildcards,
 }
 
 static void
 }
 
 static void
-set_random_key(struct sw_flow_key *key, uint16_t wildcards)
+set_random_key(struct sw_flow_key *key, uint32_t wildcards)
 {
        key->nw_src = random32();
        key->nw_dst = random32();
 {
        key->nw_src = random32();
        key->nw_dst = random32();
@@ -156,7 +156,7 @@ struct flow_key_entry {
  */
 
 static struct flow_key_entry *
  */
 
 static struct flow_key_entry *
-allocate_random_keys(int n_keys, uint16_t wildcards)
+allocate_random_keys(int n_keys, uint32_t wildcards)
 {
        struct flow_key_entry *entries, *pos;
        struct list_head *keys;
 {
        struct flow_key_entry *entries, *pos;
        struct list_head *keys;
@@ -423,7 +423,7 @@ check_lookup_and_iter(struct sw_table *swt, struct list_head *deleted,
  */
 
 static int
  */
 
 static int
-iterator_test(struct sw_table *swt, int n_flows, uint16_t wildcards)
+iterator_test(struct sw_table *swt, int n_flows, uint32_t wildcards)
 {
        struct flow_key_entry *allocated, h1, h2;
        struct list_head *added, *deleted, *tmp;
 {
        struct flow_key_entry *allocated, h1, h2;
        struct list_head *added, *deleted, *tmp;
@@ -506,7 +506,7 @@ iterator_test_destr:
  */
 
 static int
  */
 
 static int
-add_test(struct sw_table *swt, uint16_t wildcards)
+add_test(struct sw_table *swt, uint32_t wildcards)
 {
        struct flow_key_entry *allocated, h1, h2;
        struct list_head *added, *deleted, *tmp, *tmp2;
 {
        struct flow_key_entry *allocated, h1, h2;
        struct list_head *added, *deleted, *tmp, *tmp2;
@@ -599,7 +599,7 @@ add_test_destr:
  */
 
 static int
  */
 
 static int
-delete_test(struct sw_table *swt, uint16_t wildcards)
+delete_test(struct sw_table *swt, uint32_t wildcards)
 {
        struct flow_key_entry *allocated, h1, h2;
        struct list_head *added, *deleted, *tmp, *tmp2;
 {
        struct flow_key_entry *allocated, h1, h2;
        struct list_head *added, *deleted, *tmp, *tmp2;
@@ -700,7 +700,7 @@ delete_test_destr:
  */
 
 static int
  */
 
 static int
-complex_add_delete_test(struct sw_table *swt, int n_flows, int i, uint16_t wildcards)
+complex_add_delete_test(struct sw_table *swt, int n_flows, int i, uint32_t wildcards)
 {
        struct flow_key_entry *allocated, h1, h2;
        struct list_head *added, *deleted, *tmp;
 {
        struct flow_key_entry *allocated, h1, h2;
        struct list_head *added, *deleted, *tmp;
index cd21673..677bf26 100644 (file)
@@ -68,7 +68,7 @@
 /* The most significant bit being set in the version field indicates an
  * experimental OpenFlow version.  
  */
 /* The most significant bit being set in the version field indicates an
  * experimental OpenFlow version.  
  */
-#define OFP_VERSION   0x88
+#define OFP_VERSION   0x89
 
 #define OFP_MAX_TABLE_NAME_LEN 32
 #define OFP_MAX_PORT_NAME_LEN  16
 
 #define OFP_MAX_TABLE_NAME_LEN 32
 #define OFP_MAX_PORT_NAME_LEN  16
@@ -330,12 +330,27 @@ enum ofp_flow_wildcards {
     OFPFW_DL_SRC   = 1 << 2,  /* Ethernet source address. */
     OFPFW_DL_DST   = 1 << 3,  /* Ethernet destination address. */
     OFPFW_DL_TYPE  = 1 << 4,  /* Ethernet frame type. */
     OFPFW_DL_SRC   = 1 << 2,  /* Ethernet source address. */
     OFPFW_DL_DST   = 1 << 3,  /* Ethernet destination address. */
     OFPFW_DL_TYPE  = 1 << 4,  /* Ethernet frame type. */
-    OFPFW_NW_SRC   = 1 << 5,  /* IP source address. */
-    OFPFW_NW_DST   = 1 << 6,  /* IP destination address. */
-    OFPFW_NW_PROTO = 1 << 7,  /* IP protocol. */
-    OFPFW_TP_SRC   = 1 << 8,  /* TCP/UDP source port. */
-    OFPFW_TP_DST   = 1 << 9,  /* TCP/UDP destination port. */
-    OFPFW_ALL      = (1 << 10) - 1
+    OFPFW_NW_PROTO = 1 << 5,  /* IP protocol. */
+    OFPFW_TP_SRC   = 1 << 6,  /* TCP/UDP source port. */
+    OFPFW_TP_DST   = 1 << 7,  /* TCP/UDP destination port. */
+
+    /* IP source address wildcard bit count.  0 is exact match, 1 ignores the
+     * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
+     * the entire field.  This is the *opposite* of the usual convention where
+     * e.g. /24 indicates that 8 bits (not 24 bits) are wildcarded. */
+    OFPFW_NW_SRC_SHIFT = 8,
+    OFPFW_NW_SRC_BITS = 6,
+    OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT,
+    OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT,
+
+    /* IP destination address wildcard bit count.  Same format as source. */
+    OFPFW_NW_DST_SHIFT = 14,
+    OFPFW_NW_DST_BITS = 6,
+    OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT,
+    OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT,
+
+    /* Wildcard all fields. */
+    OFPFW_ALL = ((1 << 20) - 1)
 };
 
 /* Values below this cutoff are 802.3 packets and the two bytes
 };
 
 /* Values below this cutoff are 802.3 packets and the two bytes
@@ -351,16 +366,16 @@ enum ofp_flow_wildcards {
 
 /* Fields to match against flows */
 struct ofp_match {
 
 /* Fields to match against flows */
 struct ofp_match {
-    uint16_t wildcards;        /* Wildcard fields. */
+    uint32_t wildcards;        /* Wildcard fields. */
     uint16_t in_port;          /* Input switch port. */
     uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */
     uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */
     uint16_t dl_vlan;          /* Input VLAN. */
     uint16_t dl_type;          /* Ethernet frame type. */
     uint16_t in_port;          /* Input switch port. */
     uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */
     uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */
     uint16_t dl_vlan;          /* Input VLAN. */
     uint16_t dl_type;          /* Ethernet frame type. */
+    uint8_t nw_proto;          /* IP protocol. */
+    uint8_t pad;               /* Align to 32-bits. */
     uint32_t nw_src;           /* IP source address. */
     uint32_t nw_dst;           /* IP destination address. */
     uint32_t nw_src;           /* IP source address. */
     uint32_t nw_dst;           /* IP destination address. */
-    uint8_t nw_proto;          /* IP protocol. */
-    uint8_t pad[3];            /* Align to 32-bits. */
     uint16_t tp_src;           /* TCP/UDP source port. */
     uint16_t tp_dst;           /* TCP/UDP destination port. */
 };
     uint16_t tp_src;           /* TCP/UDP source port. */
     uint16_t tp_dst;           /* TCP/UDP destination port. */
 };
index ea73cb1..83b7184 100644 (file)
@@ -168,6 +168,7 @@ BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header));
 #define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15)
 #define IP_IHL_VER(ihl, ver) (((ver) << 4) | (ihl))
 
 #define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15)
 #define IP_IHL_VER(ihl, ver) (((ver) << 4) | (ihl))
 
+#define IP_TYPE_ICMP 1
 #define IP_TYPE_TCP 6
 #define IP_TYPE_UDP 17
 
 #define IP_TYPE_TCP 6
 #define IP_TYPE_UDP 17
 
index f462449..8329e30 100644 (file)
@@ -449,12 +449,51 @@ static void print_wild(struct ds *string, const char *leader, int is_wild,
     ds_put_char(string, ',');
 }
 
     ds_put_char(string, ',');
 }
 
+static void
+print_ip_netmask(struct ds *string, const char *leader, uint32_t ip,
+                 uint32_t wild_bits, int verbosity)
+{
+    if (wild_bits >= 32 && verbosity < 2) {
+        return;
+    }
+    ds_put_cstr(string, leader);
+    if (wild_bits < 32) {
+        ds_put_format(string, IP_FMT, IP_ARGS(&ip));
+        if (wild_bits) {
+            ds_put_format(string, "/%d", 32 - wild_bits);
+        }
+    } else {
+        ds_put_char(string, '*');
+    }
+    ds_put_char(string, ',');
+}
+
 /* Pretty-print the ofp_match structure */
 static void ofp_print_match(struct ds *f, const struct ofp_match *om, 
         int verbosity)
 {
 /* Pretty-print the ofp_match structure */
 static void ofp_print_match(struct ds *f, const struct ofp_match *om, 
         int verbosity)
 {
-    uint16_t w = ntohs(om->wildcards);
-
+    uint32_t w = ntohl(om->wildcards);
+    bool skip_type = false;
+    bool skip_proto = false;
+
+    if (!(w & OFPFW_DL_TYPE) &&om->dl_type == htons(ETH_TYPE_IP)) {
+        skip_type = true;
+        if (!(w & OFPFW_NW_PROTO)) {
+            skip_proto = true;
+            if (om->nw_proto == IP_TYPE_ICMP) {
+                ds_put_cstr(f, "icmp,");
+            } else if (om->nw_proto == IP_TYPE_TCP) {
+                ds_put_cstr(f, "tcp,");
+            } else if (om->nw_proto == IP_TYPE_UDP) {
+                ds_put_cstr(f, "udp,");
+            } else {
+                ds_put_cstr(f, "ip,");
+                skip_proto = false;
+            }
+        } else {
+            ds_put_cstr(f, "ip,");
+        }
+    }
     print_wild(f, "in_port=", w & OFPFW_IN_PORT, verbosity,
                "%d", ntohs(om->in_port));
     print_wild(f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
     print_wild(f, "in_port=", w & OFPFW_IN_PORT, verbosity,
                "%d", ntohs(om->in_port));
     print_wild(f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
@@ -463,14 +502,18 @@ static void ofp_print_match(struct ds *f, const struct ofp_match *om,
                ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
     print_wild(f, "dl_dst=", w & OFPFW_DL_DST, verbosity,
                ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst));
                ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
     print_wild(f, "dl_dst=", w & OFPFW_DL_DST, verbosity,
                ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst));
-    print_wild(f, "dl_type=", w & OFPFW_DL_TYPE, verbosity,
-               "0x%04x", ntohs(om->dl_type));
-    print_wild(f, "nw_src=", w & OFPFW_NW_SRC, verbosity,
-               IP_FMT, IP_ARGS(&om->nw_src));
-    print_wild(f, "nw_dst=", w & OFPFW_NW_DST, verbosity,
-               IP_FMT, IP_ARGS(&om->nw_dst));
-    print_wild(f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
-               "%u", om->nw_proto);
+    if (!skip_type) {
+        print_wild(f, "dl_type=", w & OFPFW_DL_TYPE, verbosity,
+                   "0x%04x", ntohs(om->dl_type));
+    }
+    print_ip_netmask(f, "nw_src=", om->nw_src,
+                     (w & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT, verbosity);
+    print_ip_netmask(f, "nw_dst=", om->nw_dst,
+                     (w & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT, verbosity);
+    if (!skip_proto) {
+        print_wild(f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
+                   "%u", om->nw_proto);
+    }
     print_wild(f, "tp_src=", w & OFPFW_TP_SRC, verbosity,
                "%d", ntohs(om->tp_src));
     print_wild(f, "tp_dst=", w & OFPFW_TP_DST, verbosity,
     print_wild(f, "tp_src=", w & OFPFW_TP_SRC, verbosity,
                "%d", ntohs(om->tp_src));
     print_wild(f, "tp_dst=", w & OFPFW_TP_DST, verbosity,
index 6dfba22..7df6d27 100644 (file)
@@ -500,7 +500,7 @@ make_add_flow(const struct flow *flow, uint32_t buffer_id,
     ofm->header.version = OFP_VERSION;
     ofm->header.type = OFPT_FLOW_MOD;
     ofm->header.length = htons(size);
     ofm->header.version = OFP_VERSION;
     ofm->header.type = OFPT_FLOW_MOD;
     ofm->header.length = htons(size);
-    ofm->match.wildcards = htons(0);
+    ofm->match.wildcards = htonl(0);
     ofm->match.in_port = flow->in_port;
     memcpy(ofm->match.dl_src, flow->dl_src, sizeof ofm->match.dl_src);
     memcpy(ofm->match.dl_dst, flow->dl_dst, sizeof ofm->match.dl_dst);
     ofm->match.in_port = flow->in_port;
     memcpy(ofm->match.dl_src, flow->dl_src, sizeof ofm->match.dl_src);
     memcpy(ofm->match.dl_dst, flow->dl_dst, sizeof ofm->match.dl_dst);
index f9f4a8d..77b3aae 100644 (file)
@@ -747,7 +747,7 @@ fill_flow_stats(struct buffer *buffer, struct sw_flow *flow,
     ofs->length          = htons(length);
     ofs->table_id        = table_idx;
     ofs->pad             = 0;
     ofs->length          = htons(length);
     ofs->table_id        = table_idx;
     ofs->pad             = 0;
-    ofs->match.wildcards = htons(flow->key.wildcards);
+    ofs->match.wildcards = htonl(flow->key.wildcards);
     ofs->match.in_port   = flow->key.flow.in_port;
     memcpy(ofs->match.dl_src, flow->key.flow.dl_src, ETH_ADDR_LEN);
     memcpy(ofs->match.dl_dst, flow->key.flow.dl_dst, ETH_ADDR_LEN);
     ofs->match.in_port   = flow->key.flow.in_port;
     memcpy(ofs->match.dl_src, flow->key.flow.dl_src, ETH_ADDR_LEN);
     memcpy(ofs->match.dl_dst, flow->key.flow.dl_dst, ETH_ADDR_LEN);
@@ -756,7 +756,7 @@ fill_flow_stats(struct buffer *buffer, struct sw_flow *flow,
     ofs->match.nw_src    = flow->key.flow.nw_src;
     ofs->match.nw_dst    = flow->key.flow.nw_dst;
     ofs->match.nw_proto  = flow->key.flow.nw_proto;
     ofs->match.nw_src    = flow->key.flow.nw_src;
     ofs->match.nw_dst    = flow->key.flow.nw_dst;
     ofs->match.nw_proto  = flow->key.flow.nw_proto;
-    memset(ofs->match.pad, 0, sizeof ofs->match.pad);
+    ofs->match.pad       = 0;
     ofs->match.tp_src    = flow->key.flow.tp_src;
     ofs->match.tp_dst    = flow->key.flow.tp_dst;
     ofs->duration        = htonl(now - flow->created);
     ofs->match.tp_src    = flow->key.flow.tp_src;
     ofs->match.tp_dst    = flow->key.flow.tp_dst;
     ofs->duration        = htonl(now - flow->created);
index eea201c..9c9538d 100644 (file)
 #include "timeval.h"
 
 /* Internal function used to compare fields in flow. */
 #include "timeval.h"
 
 /* Internal function used to compare fields in flow. */
-static inline
-int flow_fields_match(const struct flow *a, const struct flow *b, uint16_t w)
+static inline int
+flow_fields_match(const struct flow *a, const struct flow *b, uint16_t w,
+                  uint32_t src_mask, uint32_t dst_mask)
 {
     return ((w & OFPFW_IN_PORT || a->in_port == b->in_port)
             && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan)
 {
     return ((w & OFPFW_IN_PORT || a->in_port == b->in_port)
             && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan)
-            && (w & OFPFW_DL_SRC || !memcmp(a->dl_src, b->dl_src, ETH_ADDR_LEN))
-            && (w & OFPFW_DL_DST || !memcmp(a->dl_dst, b->dl_dst, ETH_ADDR_LEN))
+            && (w & OFPFW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src))
+            && (w & OFPFW_DL_DST || eth_addr_equals(a->dl_dst, b->dl_dst))
             && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type)
             && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type)
-            && (w & OFPFW_NW_SRC || a->nw_src == b->nw_src)
-            && (w & OFPFW_NW_DST || a->nw_dst == b->nw_dst)
+            && !((a->nw_src ^ b->nw_src) & src_mask)
+            && !((a->nw_dst ^ b->nw_dst) & dst_mask)
             && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto)
             && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src)
             && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst));
 }
 
             && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto)
             && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src)
             && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst));
 }
 
+static uint32_t make_nw_mask(int n_wild_bits)
+{
+    n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1;
+    return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0;
+}
+
+/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal
+ * modulo wildcards in 'b', zero otherwise. */
+inline int
+flow_matches_1wild(const struct sw_flow_key *a, const struct sw_flow_key *b)
+{
+    return flow_fields_match(&a->flow, &b->flow, b->wildcards,
+                             b->nw_src_mask, b->nw_dst_mask);
+}
+
 /* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal
 /* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal
- * modulo wildcards, zero otherwise. */
-inline
-int flow_matches(const struct sw_flow_key *a, const struct sw_flow_key *b)
+ * modulo wildcards in 'a' or 'b', zero otherwise. */
+inline int
+flow_matches_2wild(const struct sw_flow_key *a, const struct sw_flow_key *b)
 {
 {
-    return flow_fields_match(&a->flow, &b->flow, a->wildcards | b->wildcards);
+    return flow_fields_match(&a->flow, &b->flow, a->wildcards | b->wildcards,
+                             a->nw_src_mask & b->nw_src_mask,
+                             a->nw_dst_mask & b->nw_dst_mask);
 }
 
 /* Returns nonzero if 't' (the table entry's key) and 'd' (the key 
 }
 
 /* Returns nonzero if 't' (the table entry's key) and 'd' (the key 
@@ -71,18 +89,19 @@ int flow_matches(const struct sw_flow_key *a, const struct sw_flow_key *b)
  * equal modulo wildcards, zero otherwise.  If 'strict' is nonzero, the
  * wildcards must match in both 't_key' and 'd_key'.  Note that the
  * table's wildcards are ignored unless 'strict' is set. */
  * equal modulo wildcards, zero otherwise.  If 'strict' is nonzero, the
  * wildcards must match in both 't_key' and 'd_key'.  Note that the
  * table's wildcards are ignored unless 'strict' is set. */
-inline
-int flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict)
+int
+flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict)
 {
 {
-    if (strict && t->wildcards != d->wildcards)
+    if (strict && d->wildcards != t->wildcards) {
         return 0;
         return 0;
-
-    return flow_fields_match(&t->flow, &d->flow, d->wildcards);
+    }
+    return flow_matches_1wild(t, d);
 }
 
 }
 
-void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
+void
+flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
 {
 {
-    to->wildcards = ntohs(from->wildcards) & OFPFW_ALL;
+    to->wildcards = ntohl(from->wildcards) & OFPFW_ALL;
     to->flow.reserved = 0;
     to->flow.in_port = from->in_port;
     to->flow.dl_vlan = from->dl_vlan;
     to->flow.reserved = 0;
     to->flow.in_port = from->in_port;
     to->flow.dl_vlan = from->dl_vlan;
@@ -94,7 +113,7 @@ void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
     to->flow.tp_src = to->flow.tp_dst = 0;
 
 #define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST)
     to->flow.tp_src = to->flow.tp_dst = 0;
 
 #define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST)
-#define OFPFW_NW (OFPFW_NW_SRC | OFPFW_NW_DST | OFPFW_NW_PROTO)
+#define OFPFW_NW (OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_NW_PROTO)
     if (to->wildcards & OFPFW_DL_TYPE) {
         /* Can't sensibly match on network or transport headers if the
          * data link type is unknown. */
     if (to->wildcards & OFPFW_DL_TYPE) {
         /* Can't sensibly match on network or transport headers if the
          * data link type is unknown. */
@@ -124,11 +143,16 @@ void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
          * instead of falling into table-linear. */
         to->wildcards &= ~(OFPFW_NW | OFPFW_TP);
     }
          * instead of falling into table-linear. */
         to->wildcards &= ~(OFPFW_NW | OFPFW_TP);
     }
+
+       /* We set these late because code above adjusts to->wildcards. */
+       to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT);
+       to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT);
 }
 
 }
 
-void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from)
+void
+flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from)
 {
 {
-    to->wildcards = htons(from->wildcards);
+    to->wildcards = htonl(from->wildcards);
     to->in_port   = from->flow.in_port;
     to->dl_vlan   = from->flow.dl_vlan;
     memcpy(to->dl_src, from->flow.dl_src, ETH_ADDR_LEN);
     to->in_port   = from->flow.in_port;
     to->dl_vlan   = from->flow.dl_vlan;
     memcpy(to->dl_src, from->flow.dl_src, ETH_ADDR_LEN);
@@ -139,12 +163,13 @@ void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from)
     to->nw_proto  = from->flow.nw_proto;
     to->tp_src        = from->flow.tp_src;
     to->tp_dst        = from->flow.tp_dst;
     to->nw_proto  = from->flow.nw_proto;
     to->tp_src        = from->flow.tp_src;
     to->tp_dst        = from->flow.tp_dst;
-    memset(to->pad, '\0', sizeof(to->pad));
+    to->pad           = 0;
 }
 
 /* Allocates and returns a new flow with 'n_actions' action, using allocation
  * flags 'flags'.  Returns the new flow or a null pointer on failure. */
 }
 
 /* Allocates and returns a new flow with 'n_actions' action, using allocation
  * flags 'flags'.  Returns the new flow or a null pointer on failure. */
-struct sw_flow *flow_alloc(int n_actions)
+struct sw_flow *
+flow_alloc(int n_actions)
 {
     struct sw_flow *flow = malloc(sizeof *flow);
     if (!flow)
 {
     struct sw_flow *flow = malloc(sizeof *flow);
     if (!flow)
@@ -160,7 +185,8 @@ struct sw_flow *flow_alloc(int n_actions)
 }
 
 /* Frees 'flow' immediately. */
 }
 
 /* Frees 'flow' immediately. */
-void flow_free(struct sw_flow *flow)
+void
+flow_free(struct sw_flow *flow)
 {
     if (!flow) {
         return; 
 {
     if (!flow) {
         return; 
@@ -170,10 +196,11 @@ void flow_free(struct sw_flow *flow)
 }
 
 /* Prints a representation of 'key' to the kernel log. */
 }
 
 /* Prints a representation of 'key' to the kernel log. */
-void print_flow(const struct sw_flow_key *key)
+void
+print_flow(const struct sw_flow_key *key)
 {
     const struct flow *f = &key->flow;
 {
     const struct flow *f = &key->flow;
-    printf("wild%04x port%04x:vlan%04x mac%02x:%02x:%02x:%02x:%02x:%02x"
+    printf("wild%08x port%04x:vlan%04x mac%02x:%02x:%02x:%02x:%02x:%02x"
            "->%02x:%02x:%02x:%02x:%02x:%02x "
            "proto%04x ip%u.%u.%u.%u->%u.%u.%u.%u port%d->%d\n",
            key->wildcards, ntohs(f->in_port), ntohs(f->dl_vlan),
            "->%02x:%02x:%02x:%02x:%02x:%02x "
            "proto%04x ip%u.%u.%u.%u->%u.%u.%u.%u port%d->%d\n",
            key->wildcards, ntohs(f->in_port), ntohs(f->dl_vlan),
index 8da8534..0f6c721 100644 (file)
@@ -44,6 +44,8 @@ struct ofp_match;
 struct sw_flow_key {
     struct flow flow;           /* Flow data (in network byte order). */
     uint32_t wildcards;         /* Wildcard fields (in host byte order). */
 struct sw_flow_key {
     struct flow flow;           /* Flow data (in network byte order). */
     uint32_t wildcards;         /* Wildcard fields (in host byte order). */
+    uint32_t nw_src_mask;       /* 1-bit in each significant nw_src bit. */
+    uint32_t nw_dst_mask;       /* 1-bit in each significant nw_dst bit. */
 };
 
 struct sw_flow {
 };
 
 struct sw_flow {
@@ -68,7 +70,8 @@ struct sw_flow {
     struct ofp_action *actions;
 };
 
     struct ofp_action *actions;
 };
 
-int flow_matches(const struct sw_flow_key *, const struct sw_flow_key *);
+int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *);
+int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *);
 int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *, 
                      int);
 struct sw_flow *flow_alloc(int n_actions);
 int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *, 
                      int);
 struct sw_flow *flow_alloc(int n_actions);
index 9b63290..90fd87a 100644 (file)
@@ -180,7 +180,7 @@ static int table_hash_iterate(struct sw_table *swt,
 
         for (i = position->private[0]; i <= th->bucket_mask; i++) {
             struct sw_flow *flow = th->buckets[i];
 
         for (i = position->private[0]; i <= th->bucket_mask; i++) {
             struct sw_flow *flow = th->buckets[i];
-            if (flow && flow_matches(key, &flow->key)) {
+            if (flow && flow_matches_1wild(&flow->key, key)) {
                 int error = callback(flow, private);
                 if (error) {
                     position->private[0] = i + 1;
                 int error = callback(flow, private);
                 if (error) {
                     position->private[0] = i + 1;
index fa87763..ea3777f 100644 (file)
@@ -55,7 +55,7 @@ static struct sw_flow *table_linear_lookup(struct sw_table *swt,
     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
     struct sw_flow *flow;
     LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) {
     struct sw_table_linear *tl = (struct sw_table_linear *) swt;
     struct sw_flow *flow;
     LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) {
-        if (flow_matches(&flow->key, key))
+        if (flow_matches_1wild(key, &flow->key))
             return flow;
     }
     return NULL;
             return flow;
     }
     return NULL;
@@ -73,7 +73,7 @@ static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
     LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) {
         if (f->priority == flow->priority
                 && f->key.wildcards == flow->key.wildcards
     LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) {
         if (f->priority == flow->priority
                 && f->key.wildcards == flow->key.wildcards
-                && flow_matches(&f->key, &flow->key)) {
+                && flow_matches_2wild(&f->key, &flow->key)) {
             flow->serial = f->serial;
             list_replace(&flow->node, &f->node);
             list_replace(&flow->iter_node, &f->iter_node);
             flow->serial = f->serial;
             list_replace(&flow->node, &f->node);
             list_replace(&flow->iter_node, &f->iter_node);
@@ -166,7 +166,7 @@ static int table_linear_iterate(struct sw_table *swt,
 
     start = ~position->private[0];
     LIST_FOR_EACH (flow, struct sw_flow, iter_node, &tl->iter_flows) {
 
     start = ~position->private[0];
     LIST_FOR_EACH (flow, struct sw_flow, iter_node, &tl->iter_flows) {
-        if (flow->serial <= start && flow_matches(key, &flow->key)) {
+        if (flow->serial <= start && flow_matches_2wild(key, &flow->key)) {
             int error = callback(flow, private);
             if (error) {
                 position->private[0] = ~(flow->serial - 1);
             int error = callback(flow, private);
             if (error) {
                 position->private[0] = ~(flow->serial - 1);
index 7084ad7..a7aaf1f 100644 (file)
@@ -205,12 +205,15 @@ specified as a integer between 0 and 65535, inclusive, either in
 decimal or as a hexadecimal number prefixed by \fB0x\fR,
 e.g. \fB0x0806\fR to match ARP packets.
 
 decimal or as a hexadecimal number prefixed by \fB0x\fR,
 e.g. \fB0x0806\fR to match ARP packets.
 
-.IP \fBnw_src=\fIip\fR
+.IP \fBnw_src=\fIip\fR[\fB/\fInetmask\fR]
 Matches IPv4 source address \fIip\fR, which should be specified as an
 IP address or host name, e.g. \fB192.168.1.1\fR or
 Matches IPv4 source address \fIip\fR, which should be specified as an
 IP address or host name, e.g. \fB192.168.1.1\fR or
-\fBwww.example.com\fR.
+\fBwww.example.com\fR.  The optional \fInetmask\fR allows matching
+only on an IPv4 address prefix.  It may be specified as a dotted quad
+(e.g. \fB192.168.1.0/255.255.255.0\fR) or as a count of bits
+(e.g. \fB192.168.1.0/24\fR).
 
 
-.IP \fBnw_dst=\fInw_dst\fR
+.IP \fBnw_dst=\fIip\fR[\fB/\fInetmask\fR]
 Matches IPv4 destination address \fIip\fR.
 
 .IP \fBnw_proto=\fIproto\fR
 Matches IPv4 destination address \fIip\fR.
 
 .IP \fBnw_proto=\fIproto\fR
index f969412..37ee659 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <config.h>
  */
 
 #include <config.h>
+#include <arpa/inet.h>
 #include <errno.h>
 #include <getopt.h>
 #include <inttypes.h>
 #include <errno.h>
 #include <getopt.h>
 #include <inttypes.h>
@@ -405,8 +406,12 @@ do_dump_tables(int argc, char *argv[])
 static uint32_t
 str_to_int(const char *str) 
 {
 static uint32_t
 str_to_int(const char *str) 
 {
+    char *tail;
     uint32_t value;
     uint32_t value;
-    if (sscanf(str, "%"SCNu32, &value) != 1) {
+
+    errno = 0;
+    value = strtoul(str, &tail, 0);
+    if (errno == EINVAL || errno == ERANGE || *tail) {
         fatal(0, "invalid numeric format %s", str);
     }
     return value;
         fatal(0, "invalid numeric format %s", str);
     }
     return value;
@@ -421,17 +426,57 @@ str_to_mac(const char *str, uint8_t mac[6])
     }
 }
 
     }
 }
 
-static void
-str_to_ip(const char *str, uint32_t *ip) 
+static uint32_t
+str_to_ip(const char *str_, uint32_t *ip)
 {
 {
+    char *str = xstrdup(str_);
+    char *save_ptr = NULL;
+    const char *name, *netmask;
     struct in_addr in_addr;
     struct in_addr in_addr;
-    int retval;
+    int n_wild, retval;
 
 
-    retval = lookup_ip(str, &in_addr);
+    name = strtok_r(str, "//", &save_ptr);
+    retval = name ? lookup_ip(name, &in_addr) : EINVAL;
     if (retval) {
         fatal(0, "%s: could not convert to IP address", str);
     }
     *ip = in_addr.s_addr;
     if (retval) {
         fatal(0, "%s: could not convert to IP address", str);
     }
     *ip = in_addr.s_addr;
+
+    netmask = strtok_r(NULL, "//", &save_ptr);
+    if (netmask) {
+        uint8_t o[4];
+        if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8,
+                   &o[0], &o[1], &o[2], &o[3]) == 4) {
+            uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3];
+            int i;
+
+            /* Find first 1-bit. */
+            for (i = 0; i < 32; i++) {
+                if (nm & (1u << i)) {
+                    break;
+                }
+            }
+            n_wild = i;
+
+            /* Verify that the rest of the bits are 1-bits. */
+            for (; i < 32; i++) {
+                if (!(nm & (1u << i))) {
+                    fatal(0, "%s: %s is not a valid netmask", str, netmask);
+                }
+            }
+        } else {
+            int prefix = atoi(netmask);
+            if (prefix <= 0 || prefix > 32) {
+                fatal(0, "%s: network prefix bits not between 1 and 32", str);
+            }
+            n_wild = 32 - prefix;
+        }
+    } else {
+        n_wild = 0;
+    }
+
+    free(str);
+    return n_wild;
 }
 
 static void
 }
 
 static void
@@ -510,7 +555,7 @@ str_to_flow(char *string, struct ofp_match *match,
         const char *name;
         uint32_t wildcard;
         enum { F_U8, F_U16, F_MAC, F_IP } type;
         const char *name;
         uint32_t wildcard;
         enum { F_U8, F_U16, F_MAC, F_IP } type;
-        size_t offset;
+        size_t offset, shift;
     };
 
 #define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER)
     };
 
 #define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER)
@@ -520,8 +565,10 @@ str_to_flow(char *string, struct ofp_match *match,
         { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src) },
         { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst) },
         { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type) },
         { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src) },
         { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst) },
         { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type) },
-        { "nw_src", OFPFW_NW_SRC, F_IP, F_OFS(nw_src) },
-        { "nw_dst", OFPFW_NW_DST, F_IP, F_OFS(nw_dst) },
+        { "nw_src", OFPFW_NW_SRC_MASK, F_IP,
+          F_OFS(nw_src), OFPFW_NW_SRC_SHIFT },
+        { "nw_dst", OFPFW_NW_DST_MASK, F_IP,
+          F_OFS(nw_dst), OFPFW_NW_DST_SHIFT },
         { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto) },
         { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src) },
         { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst) },
         { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto) },
         { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src) },
         { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst) },
@@ -617,7 +664,7 @@ str_to_flow(char *string, struct ofp_match *match,
             } else if (f->type == F_MAC) {
                 str_to_mac(value, data);
             } else if (f->type == F_IP) {
             } else if (f->type == F_MAC) {
                 str_to_mac(value, data);
             } else if (f->type == F_IP) {
-                str_to_ip(value, data);
+                wildcards |= str_to_ip(value, data) << f->shift;
             } else {
                 NOT_REACHED();
             }
             } else {
                 NOT_REACHED();
             }
@@ -626,7 +673,7 @@ str_to_flow(char *string, struct ofp_match *match,
     if (name && !value) {
         fatal(0, "field %s missing value", name);
     }
     if (name && !value) {
         fatal(0, "field %s missing value", name);
     }
-    match->wildcards = htons(wildcards);
+    match->wildcards = htonl(wildcards);
 }
 
 static void do_dump_flows(int argc, char *argv[])
 }
 
 static void do_dump_flows(int argc, char *argv[])