This reworks lookup of rules for both table 0 and
table action translation. The result is that Table Mod settings,
which can alter the miss-behaviour of tables, including table 0,
on a per-table basis may be honoured.

Previous patches proposed by myself which build
on earlier merged patches by Andy Zhou implement the ofproto
side of Table Mod. So with this patch the feature should be complete.

This patch, nor any other patches it builds on, alter the default
behaviour of Open vSwitch. And in particular the OpenFlow1.1 behaviour
is the default regardless of which OpenFlow version is negotiated
between the switch and the controller.

An implementation detail, which lends itself to future work, is
the handling of OFPTC_TABLE_MISS_CONTINUE. If a table has this
behaviour set by Table Mod and a miss occurs then a loop is created,
skipping to the next table. It is quite easy to create
a situation where this loop covers ~255 tables which is very
expensive as the lookup for each table involves taking locks,
amongst other things. One way to do this would be to maintain
a bitmap, one bit per table, to indicate if the table has
any rules present or not.

Cc: Andy Zhou <az...@nicira.com>
Signed-off-by: Simon Horman <ho...@verge.net.au>
---
 OPENFLOW-1.1+                |   5 -
 ofproto/ofproto-dpif-xlate.c |  41 ++++---
 ofproto/ofproto-dpif.c       | 151 +++++++++++++++++++++++---
 ofproto/ofproto-dpif.h       |  19 +++-
 ofproto/ofproto.c            |  20 ++++
 ofproto/ofproto.h            |   2 +
 tests/ofproto-dpif.at        | 248 +++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 447 insertions(+), 39 deletions(-)

diff --git a/OPENFLOW-1.1+ b/OPENFLOW-1.1+
index d7c2b5f..dbd2957 100644
--- a/OPENFLOW-1.1+
+++ b/OPENFLOW-1.1+
@@ -61,11 +61,6 @@ probably incomplete.
       just fix it as the same as in_port.
       [required for OF1.1; optional for OF1.2+]
 
-    * OFPT_TABLE_MOD message.  This is new in OF1.1, so we need to
-      implement it.  It should be implemented so that the default OVS
-      behavior does not change.
-      [required for OF1.1 and OF1.2]
-
     * MPLS.  Simon Horman maintains a patch series that adds this
       feature.  This is partially merged.
       [optional for OF1.1+]
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 367dd88..5e1e73f 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -1847,6 +1847,7 @@ xlate_table_action(struct xlate_ctx *ctx,
         struct rule_dpif *rule;
         ofp_port_t old_in_port = ctx->xin->flow.in_port.ofp_port;
         uint8_t old_table_id = ctx->table_id;
+        enum rule_dpif_lookup_verdict verdict;
 
         ctx->table_id = table_id;
 
@@ -1854,29 +1855,37 @@ xlate_table_action(struct xlate_ctx *ctx,
          * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
          * have surprising behavior). */
         ctx->xin->flow.in_port.ofp_port = in_port;
-        rule_dpif_lookup_in_table(ctx->xbridge->ofproto,
-                                  &ctx->xin->flow, &ctx->xout->wc,
-                                  table_id, &rule);
+        verdict = rule_dpif_lookup_from_table(ctx->xbridge->ofproto,
+                                              &ctx->xin->flow, &ctx->xout->wc,
+                                              &ctx->table_id, &rule);
         ctx->xin->flow.in_port.ofp_port = old_in_port;
 
         if (ctx->xin->resubmit_hook) {
             ctx->xin->resubmit_hook(ctx->xin, rule, ctx->recurse);
         }
 
-        if (!rule && may_packet_in) {
-            struct xport *xport;
-
-            /* XXX
-             * check if table configuration flags
-             * OFPTC_TABLE_MISS_CONTROLLER, default.
-             * OFPTC_TABLE_MISS_CONTINUE,
-             * OFPTC_TABLE_MISS_DROP
-             * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? */
-            xport = get_ofp_port(ctx->xbridge, 
ctx->xin->flow.in_port.ofp_port);
-            choose_miss_rule(xport ? xport->config : 0,
-                             ctx->xbridge->miss_rule,
+        switch (verdict) {
+        case RULE_DPIF_LOOKUP_VERDICT_MATCH:
+            break;
+        case RULE_DPIF_LOOKUP_VERDICT_CONTROLLER:
+            if (may_packet_in) {
+                struct xport *xport;
+
+                xport = get_ofp_port(ctx->xbridge,
+                                     ctx->xin->flow.in_port.ofp_port);
+                choose_miss_rule(xport ? xport->config : 0,
+                                 ctx->xbridge->miss_rule,
+                                 ctx->xbridge->no_packet_in_rule, &rule);
+            }
+            break;
+        case RULE_DPIF_LOOKUP_VERDICT_DROP:
+            choose_miss_rule(OFPUTIL_PC_NO_PACKET_IN, NULL,
                              ctx->xbridge->no_packet_in_rule, &rule);
+            break;
+        default:
+            NOT_REACHED();
         }
+
         if (rule) {
             xlate_recursively(ctx, rule);
             rule_dpif_unref(rule);
@@ -3089,7 +3098,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out 
*xout)
     ctx.mpls_depth_delta = 0;
 
     if (!xin->ofpacts && !ctx.rule) {
-        rule_dpif_lookup(ctx.xbridge->ofproto, flow, wc, &rule);
+        ctx.table_id = rule_dpif_lookup(ctx.xbridge->ofproto, flow, wc, &rule);
         if (ctx.xin->resubmit_stats) {
             rule_dpif_credit_stats(rule, ctx.xin->resubmit_stats);
         }
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 3391594..d48de58 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4604,31 +4604,53 @@ subfacet_update_stats(struct subfacet *subfacet,
 
 /* Rules. */
 
-/* Lookup 'flow' in 'ofproto''s classifier.  If 'wc' is non-null, sets
- * the fields that were relevant as part of the lookup. */
-void
+/* Lookup 'flow' in table 0 of 'ofproto''s classifier.
+ * If 'wc' is non-null, sets * the fields that were relevant as part of
+ * the lookup. Returns the table_id where a match or miss occurred.
+ *
+ * The return value will be zero unless there was a miss and
+ * OFPTC_TABLE_MISS_CONTINUE is in effect for the sequence of tables
+ * where misses occur. */
+uint8_t
 rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
                  struct flow_wildcards *wc, struct rule_dpif **rule)
 {
-    struct ofport_dpif *port;
+    enum rule_dpif_lookup_verdict verdict;
+    uint8_t table_id = 0;
 
-    if (rule_dpif_lookup_in_table(ofproto, flow, wc, 0, rule)) {
-        return;
+    verdict = rule_dpif_lookup_from_table(ofproto, flow, wc, &table_id, rule);
+    switch (verdict) {
+    case RULE_DPIF_LOOKUP_VERDICT_MATCH:
+        break;
+    case RULE_DPIF_LOOKUP_VERDICT_CONTROLLER: {
+        struct ofport_dpif *port;
+
+        port = get_ofp_port(ofproto, flow->in_port.ofp_port);
+        if (!port) {
+            VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16,
+                         flow->in_port.ofp_port);
+        }
+        choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
+                         ofproto->no_packet_in_rule, rule);
+
+        break;
     }
-    port = get_ofp_port(ofproto, flow->in_port.ofp_port);
-    if (!port) {
-        VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16,
-                     flow->in_port.ofp_port);
+    case RULE_DPIF_LOOKUP_VERDICT_DROP:
+        choose_miss_rule(OFPUTIL_PC_NO_PACKET_IN, NULL,
+                         ofproto->no_packet_in_rule, rule);
+        break;
+    default:
+        NOT_REACHED();
     }
 
-    choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
-                     ofproto->no_packet_in_rule, rule);
+    return table_id;
 }
 
-bool
-rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
-                          const struct flow *flow, struct flow_wildcards *wc,
-                          uint8_t table_id, struct rule_dpif **rule)
+static bool
+rule_dpif_lookup_in_table__(struct ofproto_dpif *ofproto,
+                            const struct flow *flow, struct flow_wildcards *wc,
+                            uint8_t table_id, bool *is_empty,
+                            struct rule_dpif **rule)
 {
     const struct cls_rule *cls_rule;
     struct classifier *cls;
@@ -4662,11 +4684,108 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
 
     *rule = rule_dpif_cast(rule_from_cls_rule(cls_rule));
     rule_dpif_ref(*rule);
+    if (is_empty) {
+        *is_empty = classifier_is_empty(cls);
+    }
     ovs_rwlock_unlock(&cls->rwlock);
 
     return *rule != NULL;
 }
 
+bool
+rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
+                          const struct flow *flow, struct flow_wildcards *wc,
+                          uint8_t table_id, struct rule_dpif **rule)
+{
+    return rule_dpif_lookup_in_table__(ofproto, flow, wc, table_id,
+                                       NULL, rule);
+}
+
+#define OFPTC_TABLE_MISS_MAX OFPTC_TABLE_MISS_DROP
+
+/* Lookup 'flow' in 'ofproto''s classifier starting at 'table_id'.
+ *
+ * If 'wc' is non-null, sets the fields that were relevant as part
+ * of the lookup.
+ *
+ * 'table_id' is set to the table where a match or miss occurred.
+ * This value will be the input value of 'table_id' unless there was
+ * a miss and OFPTC_TABLE_MISS_CONTINUE is in effect for the sequence of
+ * tables where misses occur.
+ *
+ * The return value is:
+ * RULE_DPIF_LOOKUP_VERDICT_MATCH:      If a match occurred
+ * RULE_OFPTC_TABLE_MISS_CONTROLLER:    If a miss occurred and the packet
+ *                                      should be forwarded to the controller.
+ * RULE_OFPTC_TABLE_MISS_DROP:          If a miss occurred and the packet
+ *                                      should be dropped. */
+enum rule_dpif_lookup_verdict
+rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto,
+                            const struct flow *flow, struct flow_wildcards *wc,
+                            uint8_t *table_id, struct rule_dpif **rule)
+{
+    enum ofp_table_config config = OFPTC_TABLE_MISS_MAX;
+    uint8_t id = *table_id;
+
+    while (1) {
+        bool is_empty;
+
+        if (rule_dpif_lookup_in_table__(ofproto, flow, wc, id,
+                                        &is_empty, rule)) {
+            return RULE_DPIF_LOOKUP_VERDICT_MATCH;
+        }
+
+        if (!is_empty) {
+            *table_id = id;
+        }
+
+        if (config >= OFPTC_TABLE_MISS_MAX) {
+            config = table_get_config(&ofproto->up, id);
+            config &= OFPTC_TABLE_MISS_MASK;
+        }
+
+        /* XXX
+         * This does not take into account different
+         * behaviour for different OpenFlow versions
+         *
+         * OFPTC_TABLE_MISS_CONTINUE:   Behaviour of OpenFlow1.0
+         * OFPTC_TABLE_MISS_CONTROLLER: Default for OpenFlow1.1+
+         * OFPTC_TABLE_MISS_DROP:       Default for OpenFlow1.3+
+         *
+         * Instead the global default is OFPTC_TABLE_MISS_CONTROLLER
+         * which may be configured globally using Table Mod. */
+        switch (config) {
+        case OFPTC_TABLE_MISS_CONTINUE: {
+            id++;
+
+            if (id == TBL_INTERNAL) {
+                id++;
+            }
+
+            if (id < N_TABLES) {
+                /* XXX This may get very expensive as
+                 * each call to rule_dpif_lookup_in_table() is expensive
+                 * and this may occur up to approximately N_TABLES times.  */
+                continue;
+            }
+            /* Fall through to OFPTC_TABLE_MISS_CONTROLLER
+             * as this is the last table in the pipeline */
+        }
+        case OFPTC_TABLE_MISS_CONTROLLER:
+            return RULE_DPIF_LOOKUP_VERDICT_CONTROLLER;
+            /* Fall through to OFPTC_TABLE_MISS_DROP if
+             * PACKET_IN is not allowed */
+        case OFPTC_TABLE_MISS_DROP:
+            return RULE_DPIF_LOOKUP_VERDICT_DROP;
+        case OFPTC_TABLE_MISS_MASK:
+        default:
+            NOT_REACHED();
+        }
+    }
+
+    NOT_REACHED();
+}
+
 /* Given a port configuration (specified as zero if there's no port), chooses
  * which of 'miss_rule' and 'no_packet_in_rule' should be used in case of a
  * flow table miss. */
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index 51cb38f..dcd2eb6 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -34,6 +34,15 @@ struct dpif_backer;
 struct OVS_LOCKABLE rule_dpif;
 struct OVS_LOCKABLE group_dpif;
 
+enum rule_dpif_lookup_verdict {
+    RULE_DPIF_LOOKUP_VERDICT_MATCH,         /* A match occurred. */
+    RULE_DPIF_LOOKUP_VERDICT_CONTROLLER,    /* A miss occurred and the packet
+                                             * should be passed to
+                                             * the controller. */
+    RULE_DPIF_LOOKUP_VERDICT_DROP,          /* A miss occurred and the packet
+                                             * should be dropped. */
+};
+
 /* Ofproto-dpif -- DPIF based ofproto implementation.
  *
  * Ofproto-dpif provides an ofproto implementation for those platforms which
@@ -62,8 +71,14 @@ struct OVS_LOCKABLE group_dpif;
  *   Ofproto-dpif-xlate is responsible for translating translating OpenFlow
  *   actions into datapath actions. */
 
-void rule_dpif_lookup(struct ofproto_dpif *, const struct flow *,
-                      struct flow_wildcards *, struct rule_dpif **rule);
+uint8_t rule_dpif_lookup(struct ofproto_dpif *, const struct flow *,
+                         struct flow_wildcards *, struct rule_dpif **rule);
+
+enum rule_dpif_lookup_verdict rule_dpif_lookup_from_table(struct ofproto_dpif 
*,
+                                                          const struct flow *,
+                                                          struct 
flow_wildcards *,
+                                                          uint8_t *table_id,
+                                                          struct rule_dpif **);
 
 bool rule_dpif_lookup_in_table(struct ofproto_dpif *, const struct flow *,
                                struct flow_wildcards *, uint8_t table_id,
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index bb86d9f..92f4574 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -5776,8 +5776,28 @@ handle_group_mod(struct ofconn *ofconn, const struct 
ofp_header *oh)
     }
 }
 
+static enum ofp_table_config
+table_get_config__(const struct oftable *table)
+    OVS_EXCLUDED(table->config_rwlock)
+{
+    enum ofp_table_config config;
+
+    ovs_rwlock_rdlock(&table->config_rwlock);
+    config = table->config;
+    ovs_rwlock_unlock(&table->config_rwlock);
+
+    return config;
+}
+
+enum ofp_table_config
+table_get_config(const struct ofproto *ofproto, uint8_t table_id)
+{
+    return table_get_config__(&ofproto->tables[table_id]);
+}
+
 static void
 table_set_config(struct oftable *table, uint32_t config)
+    OVS_EXCLUDED(table->config_rwlock)
 {
     ovs_rwlock_wrlock(&table->config_rwlock);
     table->config = config;
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 903d1f4..a847609 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -436,6 +436,8 @@ bool ofproto_has_vlan_usage_changed(const struct ofproto *);
 int ofproto_port_set_realdev(struct ofproto *, ofp_port_t vlandev_ofp_port,
                              ofp_port_t realdev_ofp_port, int vid);
 
+enum ofp_table_config table_get_config(const struct ofproto *ofproto,
+                                       uint8_t table_id);
 #ifdef  __cplusplus
 }
 #endif
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 846439c..e607f9b 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -382,6 +382,254 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - Table Miss - OFPTC_TABLE_MISS_CONTROLLER])
+OVS_VSWITCHD_START([dnl
+   add-port br0 p1 -- set Interface p1 type=dummy
+])
+ON_EXIT([kill `cat ovs-ofctl.pid`])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+
+AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir 
--pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3 ; do
+    ovs-appctl netdev-dummy/receive p1 
'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+])
+
+AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+NXST_FLOW reply:
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - Table Miss - goto table and 
OFPTC_TABLE_MISS_CONTROLLER])
+OVS_VSWITCHD_START([dnl
+   add-port br0 p1 -- set Interface p1 type=dummy
+])
+ON_EXIT([kill `cat ovs-ofctl.pid`])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+AT_CHECK([ovs-ofctl -OOpenFlow12 add-flow br0 'table=0 actions=goto_table(1)'])
+
+AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir 
--pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3 ; do
+    ovs-appctl netdev-dummy/receive p1 
'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+])
+
+AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], 
[dnl
+ n_packets=3, n_bytes=180, actions=goto_table:1
+OFPST_FLOW reply (OF1.2):
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - Table Miss - OFPTC_TABLE_MISS_CONTINUE])
+OVS_VSWITCHD_START([dnl
+   add-port br0 p1 -- set Interface p1 type=dummy
+])
+ON_EXIT([kill `cat ovs-ofctl.pid`])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+AT_CHECK([ovs-ofctl add-flow br0 'table=1 dl_src=10:11:11:11:11:11 
actions=controller'])
+AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all continue])
+
+dnl Miss table 0, Hit table 1
+AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir 
--pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3 ; do
+    ovs-appctl netdev-dummy/receive p1 
'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
+done
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+])
+
+dnl Hit table 0, Miss all other tables, sent to controller
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> 
ofctl_monitor.log])
+
+for i in 1 2 3 ; do
+    ovs-appctl netdev-dummy/receive p1 
'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
+done
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via 
no_match) data_len=60 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via 
no_match) data_len=60 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via 
no_match) data_len=60 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+])
+
+AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], 
[dnl
+ table=1, n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 
actions=CONTROLLER:65535
+OFPST_FLOW reply (OF1.2):
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - Table Miss - goto table and 
OFPTC_TABLE_MISS_CONTINUE])
+OVS_VSWITCHD_START([dnl
+   add-port br0 p1 -- set Interface p1 type=dummy
+])
+ON_EXIT([kill `cat ovs-ofctl.pid`])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+AT_DATA([flows.txt], [dnl
+table=0 actions=goto_table(1)
+table=2 dl_src=10:11:11:11:11:11 actions=controller
+])
+AT_CHECK([ovs-ofctl -OOpenFlow12 add-flows br0 flows.txt])
+AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all continue])
+
+dnl Hit table 0, Miss table 1, Hit table 2
+AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir 
--pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3 ; do
+    ovs-appctl netdev-dummy/receive p1 
'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
+done
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 
(unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+])
+
+dnl Hit table 1, Miss all other tables, sent to controller
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> 
ofctl_monitor.log])
+
+for i in 1 2 3 ; do
+    ovs-appctl netdev-dummy/receive p1 
'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
+done
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via 
no_match) data_len=60 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via 
no_match) data_len=60 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+dnl
+NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via 
no_match) data_len=60 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010
 tcp_csum:0
+])
+
+AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], 
[dnl
+ n_packets=6, n_bytes=360, actions=goto_table:1
+ table=2, n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 
actions=CONTROLLER:65535
+OFPST_FLOW reply (OF1.2):
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - Table Miss - OFPTC_TABLE_MISS_DROP])
+OVS_VSWITCHD_START([dnl
+   add-port br0 p1 -- set Interface p1 type=dummy
+])
+ON_EXIT([kill `cat ovs-ofctl.pid`])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all drop])
+
+AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir 
--pidfile 2> ofctl_monitor.log])
+
+dnl Test that missed packets are droped
+for i in 1 2 3 ; do
+    ovs-appctl netdev-dummy/receive p1 
'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
+done
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+])
+
+AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+NXST_FLOW reply:
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - Table Miss - goto table and OFPTC_TABLE_MISS_DROP])
+OVS_VSWITCHD_START([dnl
+   add-port br0 p1 -- set Interface p1 type=dummy
+])
+ON_EXIT([kill `cat ovs-ofctl.pid`])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+AT_CHECK([ovs-ofctl del-flows br0])
+AT_CHECK([ovs-ofctl -OOpenFlow12 add-flow br0 'table=0 actions=goto_table(1)'])
+AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all drop])
+
+AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir 
--pidfile 2> ofctl_monitor.log])
+
+dnl Test that missed packets are droped
+for i in 1 2 3 ; do
+    ovs-appctl netdev-dummy/receive p1 
'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
+done
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+])
+
+AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], 
[dnl
+ n_packets=3, n_bytes=180, actions=goto_table:1
+OFPST_FLOW reply (OF1.2):
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - controller])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
-- 
1.8.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to