On Thu, Feb 18, 2016 at 03:54:26PM +0530, saloni.jai...@gmail.com wrote:
> From: Saloni Jain <saloni.j...@tcs.com>
> 
> On change in a table state, the controller needs to be informed with
> the OFPT_TABLE_STATUS message. The message is sent with reason
> OFPTR_VACANCY_DOWN or OFPTR_VACANCY_UP in case of change in remaining
> space eventually crossing any one of the threshold.
> 
> Signed-off-by: Saloni Jain <saloni.j...@tcs.com>
> Co-authored-by: Rishi Bamba <rishi.ba...@tcs.com>
> Signed-off-by: Rishi Bamba <rishi.ba...@tcs.com>
> ---
> difference between v9 <-> v10
> - Fixed a test case failure

This still didn't actually implement the text of the OpenFlow spec, and
in particular this initialization:

    When vacancy events are enabled on the table using the
    OFPTC_VACANCY_EVENTS flag, either the vacancy up or vacancy down
    event is enabled. When enabling events, if the current vacancy is
    less than vacancy_up, vacancy up events must be enabled, and vacancy
    down events must be disabled. When enabling events, if the current
    vacancy is greater or equal to vacancy_up, vacancy down events must
    be enabled, and vacancy up events must be disabled.

I implemented this, folding in the following incremental change, and
applied this to master.

--8<--------------------------cut here-------------------------->8--

diff --git a/NEWS b/NEWS
index 57a250e..156fc07 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ Post-v2.5.0
    - OpenFlow:
      * OpenFlow 1.1+ OFPT_QUEUE_GET_CONFIG_REQUEST now supports OFPP_ANY.
      * OpenFlow 1.4+ OFPMP_QUEUE_DESC is now supported.
+     * OpenFlow 1.4+ OFPT_TABLE_STATUS is now supported.
      * New property-based packet-in message format NXT_PACKET_IN2 with support
        for arbitrary user-provided data and for serializing flow table
        traversal into a continuation for later resumption.
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 151c5a6..de7cf3c 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -10279,8 +10279,7 @@ ofputil_decode_table_status(const struct ofp_header *oh,
     raw = ofpraw_pull_assert(&b);
     ots = ofpbuf_pull(&b, sizeof *ots);
 
-    if (raw == OFPRAW_OFPT14_TABLE_STATUS)
-    {
+    if (raw == OFPRAW_OFPT14_TABLE_STATUS) {
         if (ots->reason != OFPTR_VACANCY_DOWN
             && ots->reason != OFPTR_VACANCY_UP) {
             return OFPERR_OFPBPC_BAD_VALUE;
@@ -10289,7 +10288,6 @@ ofputil_decode_table_status(const struct ofp_header *oh,
 
         error = ofputil_decode_table_desc(&b, &ts->desc, oh->version);
         return error;
-
     } else {
         return OFPERR_OFPBRC_BAD_VERSION;
     }
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index ab1e8ec..2c6e483 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -256,8 +256,11 @@ struct oftable {
 #define EVICTION_OPENFLOW (1 << 1) /* Set to 1 if OpenFlow enables eviction. */
     unsigned int eviction;
 
-    /* If true, vacancy events are enabled; otherwise they are disabled. */
-    bool vacancy_enabled;
+    /* If zero, vacancy events are disabled.  If nonzero, this is the type of
+       vacancy event that is enabled: either OFPTR_VACANCY_DOWN or
+       OFPTR_VACANCY_UP.  Only one type of vacancy event can be enabled at a
+       time. */
+    enum ofp14_table_reason vacancy_event;
 
     /* Non-zero values for vacancy_up and vacancy_down indicates that vacancy
      * is enabled by table-mod, else these values are set to zero when
@@ -265,9 +268,6 @@ struct oftable {
     uint8_t vacancy_down; /* Vacancy threshold when space decreases (%). */
     uint8_t vacancy_up;   /* Vacancy threshold when space increases (%). */
 
-    /* Vacancy Reason sent through TABLE_STATUS */
-    enum ofp14_table_reason vacancy_reason;     /* One of OFPTR_*. */
-
     atomic_ulong n_matched;
     atomic_ulong n_missed;
 };
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 8fe6464..1335da6 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3594,26 +3594,35 @@ handle_table_features_request(struct ofconn *ofconn,
     return 0;
 }
 
+/* Returns the vacancy of 'oftable', a number that ranges from 0 (if the table
+ * is full) to 100 (if the table is empty).
+ *
+ * A table without a limit on flows is considered to be empty. */
+static uint8_t
+oftable_vacancy(const struct oftable *t)
+{
+    return (!t->max_flows ? 100
+            : t->n_flows >= t->max_flows ? 0
+            : (t->max_flows - t->n_flows) * 100.0 / t->max_flows);
+}
+
 static void
 query_table_desc__(struct ofputil_table_desc *td,
                    struct ofproto *ofproto, uint8_t table_id)
 {
-    unsigned int count = ofproto->tables[table_id].n_flows;
-    unsigned int max_flows = ofproto->tables[table_id].max_flows;
+    const struct oftable *t = &ofproto->tables[table_id];
 
     td->table_id = table_id;
-    td->eviction = (ofproto->tables[table_id].eviction & EVICTION_OPENFLOW
+    td->eviction = (t->eviction & EVICTION_OPENFLOW
                     ? OFPUTIL_TABLE_EVICTION_ON
                     : OFPUTIL_TABLE_EVICTION_OFF);
     td->eviction_flags = OFPROTO_EVICTION_FLAGS;
-    td->vacancy = (ofproto->tables[table_id].vacancy_enabled
+    td->vacancy = (t->vacancy_event
                    ? OFPUTIL_TABLE_VACANCY_ON
                    : OFPUTIL_TABLE_VACANCY_OFF);
-    td->table_vacancy.vacancy_down = ofproto->tables[table_id].vacancy_down;
-    td->table_vacancy.vacancy_up = ofproto->tables[table_id].vacancy_up;
-    td->table_vacancy.vacancy = max_flows
-                                ? ((double) (max_flows - count) / max_flows) * 
100
-                                : 0;
+    td->table_vacancy.vacancy_down = t->vacancy_down;
+    td->table_vacancy.vacancy_up = t->vacancy_up;
+    td->table_vacancy.vacancy = oftable_vacancy(t);
 }
 
 /* This function queries the database for dumping table-desc. */
@@ -3661,23 +3670,29 @@ handle_table_desc_request(struct ofconn *ofconn,
 static void
 send_table_status(struct ofproto *ofproto, uint8_t table_id)
 {
-    struct ofputil_table_desc td;
-    enum ofp14_table_reason reason;
-
-    reason = ofproto->tables[table_id].vacancy_reason;
-    query_table_desc__(&td, ofproto, table_id);
-
-    if (td.table_vacancy.vacancy < td.table_vacancy.vacancy_down
-        && reason != OFPTR_VACANCY_DOWN) {
+    struct oftable *t = &ofproto->tables[table_id];
+    if (!t->vacancy_event) {
+        return;
+    }
 
-        ofproto->tables[table_id].vacancy_reason = OFPTR_VACANCY_DOWN;
-        connmgr_send_table_status(ofproto->connmgr, &td, OFPTR_VACANCY_DOWN);
+    uint8_t vacancy = oftable_vacancy(t);
+    enum ofp14_table_reason event;
+    if (vacancy < t->vacancy_down) {
+        event = OFPTR_VACANCY_DOWN;
+    } else if (vacancy > t->vacancy_up) {
+        event = OFPTR_VACANCY_UP;
+    } else {
+        return;
+    }
 
-    } else if (td.table_vacancy.vacancy > td.table_vacancy.vacancy_up
-               && reason != OFPTR_VACANCY_UP) {
+    if (event == t->vacancy_event) {
+        struct ofputil_table_desc td;
+        query_table_desc__(&td, ofproto, table_id);
+        connmgr_send_table_status(ofproto->connmgr, &td, event);
 
-        ofproto->tables[table_id].vacancy_reason = OFPTR_VACANCY_UP;
-        connmgr_send_table_status(ofproto->connmgr, &td, OFPTR_VACANCY_UP);
+        t->vacancy_event = (event == OFPTR_VACANCY_DOWN
+                            ? OFPTR_VACANCY_UP
+                            : OFPTR_VACANCY_DOWN);
     }
 }
 
@@ -4717,12 +4732,8 @@ add_flow_finish(struct ofproto *ofproto, struct 
ofproto_flow_mod *ofm,
                          req ? req->ofconn : NULL,
                          req ? req->request->xid : 0, NULL);
 
-        /* Send Vacancy Events  for OF1.4+ when there is change in flow table.
-         * Provided OFPTC14_VACANCY_EVENTS is set for the table. */
-        if (ofproto->tables[new_rule->table_id].vacancy_enabled) {
-            send_table_status(ofproto, new_rule->table_id);
-        }
-
+        /* Send Vacancy Events for OF1.4+. */
+        send_table_status(ofproto, new_rule->table_id);
     }
 
     send_buffered_packet(req, fm->buffer_id, new_rule);
@@ -5119,12 +5130,8 @@ delete_flows_finish__(struct ofproto *ofproto,
                              req ? req->ofconn : NULL,
                              req ? req->request->xid : 0, NULL);
 
-            /* Send Vacancy Events  for OF1.4+ when there is change in flow
-             * table. Provided OFPTC14_VACANCY_EVENTS is set for the table.
-             */
-            if (ofproto->tables[rule->table_id].vacancy_enabled) {
-                send_table_status(ofproto, rule->table_id);
-            }
+            /* Send Vacancy Event for OF1.4+. */
+            send_table_status(ofproto, rule->table_id);
 
             ofproto_rule_remove__(ofproto, rule);
             learned_cookies_dec(ofproto, rule_get_actions(rule),
@@ -6785,11 +6792,16 @@ table_mod__(struct oftable *oftable,
 
     if (tm->vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
         ovs_mutex_lock(&ofproto_mutex);
-        oftable->vacancy_enabled = (tm->vacancy == OFPUTIL_TABLE_VACANCY_ON
-                                    ? OFPTC14_VACANCY_EVENTS
-                                    : 0);
         oftable->vacancy_down = tm->table_vacancy.vacancy_down;
         oftable->vacancy_up = tm->table_vacancy.vacancy_up;
+        if (tm->vacancy == OFPUTIL_TABLE_VACANCY_OFF) {
+            oftable->vacancy_event = 0;
+        } else if (!oftable->vacancy_event) {
+            uint8_t vacancy = oftable_vacancy(oftable);
+            oftable->vacancy_event = (vacancy < oftable->vacancy_up
+                                      ? OFPTR_VACANCY_UP
+                                      : OFPTR_VACANCY_DOWN);
+        }
         ovs_mutex_unlock(&ofproto_mutex);
     }
 }
diff --git a/tests/ofproto.at b/tests/ofproto.at
index d5a9c29..b2b32b5 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -2918,12 +2918,74 @@ OFPT_PORT_STATUS (OF1.4): MOD: ${INDEX}(test): 
addr:aa:55:aa:55:00:0x
     # OFPT_TABLE_STATUS, OFPTR_VACANCY_UP
     if test X"$1" = X"OFPTR_VACANCY_UP"; then shift;
         ovs-vsctl -- --id=@t1 create Flow_Table flow-limit=10 -- set bridge 
br0 flow_tables:1=@t1
+
+       # Turn on vacancy events, then add flows until we're full.
+       # With initial vacancy of 100% and vacancy_up of 80%, so that
+       # vacancy >= vacancy_up, this enables VACANY_DOWN events, so
+       # we get a single such message when vacancy dips below 20%.
         ovs-ofctl -O OpenFlow14 mod-table br0 1 vacancy:20,80
         ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=1,actions=2
         ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=2,actions=2
         ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=3,actions=2
         ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=4,actions=2
         ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=5,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=6,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=7,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=8,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=9,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=10,actions=2
+        echo >>expout "OFPT_TABLE_STATUS (OF1.4): reason=VACANCY_DOWN
+table_desc:-
+  table 1:
+   eviction=off eviction_flags=OTHER|IMPORTANCE|LIFETIME
+   vacancy=on vacancy_down=20% vacancy_up=80% vacancy=10%"
+        # Then delete flows until we're empty.  Sending the
+       # VACANCY_DOWN message enabled VACANCY_UP events, so we get a
+       # single such message when vacancy rises above 80%.
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=1
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=2
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=3
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=4
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=5
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=6
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=7
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=8
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=9
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=10
+        echo >>expout "OFPT_TABLE_STATUS (OF1.4): reason=VACANCY_UP
+table_desc:-
+  table 1:
+   eviction=off eviction_flags=OTHER|IMPORTANCE|LIFETIME
+   vacancy=on vacancy_down=20% vacancy_up=80% vacancy=90%"
+
+        # Now approach vacancy from the other direction.  First
+       # disable vacancy events.  With initial vacancy of 70%, so
+       # that vacancy < vacancy_up, this enables VACANCY_UP events.
+       # That means that filling up the table generates no message,
+       # but deleting all the flows generates VACANCY_UP at the point
+       # vacancy rises above 80%.
+        ovs-ofctl -O OpenFlow14 mod-table br0 1 novacancy
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=1,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=2,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=3,actions=2
+        ovs-ofctl -O OpenFlow14 mod-table br0 1 vacancy:20,80
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=4,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=5,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=6,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=7,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=8,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=9,actions=2
+        ovs-ofctl -O OpenFlow14 add-flow br0 table=1,in_port=10,actions=2
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=1
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=2
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=3
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=4
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=5
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=6
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=7
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=8
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=9
+        ovs-ofctl -O OpenFlow14 del-flows br0 table=1,in_port=10
         echo >>expout "OFPT_TABLE_STATUS (OF1.4): reason=VACANCY_UP
 table_desc:-
   table 1:
@@ -2956,7 +3018,7 @@ ovs-appctl -t ovs-ofctl ofctl/send 
051800180000000200000003000000000000000000000
 check_async 3 OFPPR_ADD OFPPR_MODIFY OFPPR_DELETE
 
 # Use OF 1.4 OFPT_SET_ASYNC to enable a patchwork of asynchronous messages.
-ovs-appctl -t ovs-ofctl ofctl/send 
051c0040000000020000000800000005000100080000000200020008000000020003000800000005000400080000001c00050008000000050008000800000010
+ovs-appctl -t ovs-ofctl ofctl/send 
051c0040000000020000000800000005000100080000000200020008000000020003000800000005000400080000001c00050008000000050008000800000018
 check_async 4 OFPR_INVALID_TTL OFPPR_DELETE OFPRR_DELETE OFPRR_GROUP_DELETE 
OFPTR_VACANCY_UP
 
 # Set controller ID 123.
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to