vswitchd: Don't reset idle timer when updating flows.
authorBen Pfaff <blp@nicira.com>
Fri, 16 Jan 2009 18:23:51 +0000 (10:23 -0800)
committerBen Pfaff <blp@nicira.com>
Fri, 16 Jan 2009 18:23:51 +0000 (10:23 -0800)
When a flow was revalidated, we would use a OFPFC_ADD flow_mod message to
change the flow's actions.  However, this resets the idle-timer countdown.
In extreme circumstances, such as when VMs are being continuously migrated,
this meant that completely idle flows would never expire, because their
idle timers would keep getting reset more often than every 5 seconds, and
so the flow table would keep growing, never shrinking.

Now, when we revalidate an existing flow and update its actions, we use
an OFPFC_MODIFY_STRICT flow_mod message, which also updates actions but
does not reset the idle-timer countdown.

vswitchd/bridge.c

index 4934092bb5012fb57b581dabc0b84193195d32bf..fd7deb27f3e9a1a29bf21f2587bda4c60354e5f2 100644 (file)
@@ -1549,13 +1549,16 @@ send_packets(struct bridge *br, const struct flow *flow,
 
     if (setup_flow) {
         struct ft_flow *f;
-        bool queue;
+        int command;
 
         f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
         if (f) {
             if (!ftd_equal(dsts, n_dsts, f->dsts, f->n_dsts)) {
+                /* Update the flow.  Use OFPFC_MODIFY_STRICT instead of
+                 * OFPFC_ADD so that we don't reset the idle-timer
+                 * countdown for this flow. */
                 ftf_set_dsts(f, dsts, n_dsts);
-                queue = true;
+                command = OFPFC_MODIFY_STRICT;
             } else {
                 /* Correct flow is already in the flow table, nothing to do.
                  * This should only happen on revalidate, since
@@ -1563,20 +1566,24 @@ send_packets(struct bridge *br, const struct flow *flow,
                  * no-match packet-in message.  (If it could happen in other
                  * circumstances then we'd want to arrange to send a packet-out
                  * below, but there's no need.) */
-                queue = false;
+                command = -1;
             }
             f->tags = tags;
         } else {
             f = ftf_create(flow, dsts, n_dsts, tags);
             ft_insert(br->ft, f);
-            queue = true;
+            command = OFPFC_ADD;
         }
         f->need_drop = false;
 
-        if (queue) {
-            struct ofpbuf *fbuf = make_add_flow(flow, pkt->buffer_id,
-                                                br->flow_idle_time,
-                                                actions_len);
+        if (command >= 0) {
+            struct ofp_flow_mod *ofm;
+            struct ofpbuf *fbuf;
+
+            fbuf = make_add_flow(flow, pkt->buffer_id, br->flow_idle_time,
+                                 actions_len);
+            ofm = fbuf->data;
+            ofm->command = htons(command);
             put_actions(dsts, n_dsts, ntohs(flow->dl_vlan), fbuf);
             queue_tx(br, fbuf);