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 6d9a8fe7aab260e63355c8756ba869f4d1edc0d4..5c3a84c4f3551abdbd7e0f4e8af6d98e2b84b5d1 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 afd91bf9240499d6b4f5cae4ea04f7de797a082e..a2c96abd6348a747b9df20fb019716949dd64324 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 3438d96c25acddb7a94b1a03d886bf816f38ddd0..00445f4aaaa07f36979e76f742b5c215e8bb33ea 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 d6699b9d118b25f6e2717eae22825c86d692d664..6f21e1de9d5d8452ca4beb901218275bb276094d 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 1c0c6e73823c5bb2875e125e7b5aeb0030361c00..46acf80e39f256bd84a1303cb20076b11d7a5d62 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 d2d7e3c7cfb72be3b4bc8aca4acea6e7f3e1949c..e7c6e673902e6b9d0e05db20d9bbc676dc18c460 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 3cc6a58df4e742e47690178461f2af9365773c24..5f7cd1cb4790fb3fe61425bf638251d39e1f11c7 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 cd216736cd024bb1833864b9d96fd3eb01851771..677bf263e09795a18d1048c224d713b4e402dd72 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 ea73cb14906da41bf453817fbffecac6a7a343c3..83b71849244d28b629d96e1e247e26ec88fedf52 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 f462449d9ca46d491bba85874114067447d1739f..8329e30440f266e3ca1296be4059708fcf1c6eb9 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 6dfba22c1da84647d71e924aa1709469ae086cd5..7df6d27b2ceb7d22c144a7b5d670f4240e5ded24 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 f9f4a8db827b65a9d60f35b1ce4e547b1fd217ab..77b3aaec32e50c4e2ca6ffc4b454547a3fd07851 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 eea201c0a2dc8b8ad60c87809c5f43f9883b2eb2..9c9538d0eeba5ba0413e7caa3851e00b5caea242 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 8da85344461387d7c2be268e47f326c2b82b0418..0f6c72161a2e1e97ec2f03cc4dce63a621d5403b 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 9b632905e27c99046c157829563da6cfc3420f70..90fd87aaef693957ff2b26afabc918a9ccd22eff 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 fa87763bf7a922fcf938842ebb09082f781cb83c..ea3777f2737d3c5d18016d2c3e324cb7a0d354fe 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 7084ad7e9f82d8e66cc48cd8750692f89ec6d51f..a7aaf1f35e29969b34609a22a094c45d20678cd0 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 f9694123664ed684ad6d2d5f7533377ee50d0172..37ee65974a3d8c8071b4cd0ab580da53679a81ae 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[])