ofproto: Send only one OFPT_FLOW_REMOVED message when a flow expires.
[sliver-openvswitch.git] / ofproto / ofproto.c
index b1c93fb..f67e1fb 100644 (file)
@@ -241,6 +241,7 @@ static long long int ofport_get_usage(const struct ofproto *,
                                       ofp_port_t ofp_port);
 static void ofport_set_usage(struct ofproto *, ofp_port_t ofp_port,
                              long long int last_used);
+static void ofport_remove_usage(struct ofproto *, ofp_port_t ofp_port);
 
 /* Ofport usage.
  *
@@ -1138,7 +1139,8 @@ ofproto_get_snoops(const struct ofproto *ofproto, struct sset *snoops)
 }
 
 static void
-ofproto_rule_delete__(struct ofproto *ofproto, struct rule *rule)
+ofproto_rule_delete__(struct ofproto *ofproto, struct rule *rule,
+                      uint8_t reason)
     OVS_REQUIRES(ofproto_mutex)
 {
     struct ofopgroup *group;
@@ -1146,7 +1148,7 @@ ofproto_rule_delete__(struct ofproto *ofproto, struct rule *rule)
     ovs_assert(!rule->pending);
 
     group = ofopgroup_create_unattached(ofproto);
-    delete_flow__(rule, group, OFPRR_DELETE);
+    delete_flow__(rule, group, reason);
     ofopgroup_submit(group);
 }
 
@@ -1201,7 +1203,7 @@ ofproto_flush__(struct ofproto *ofproto)
         ovs_rwlock_unlock(&table->cls.rwlock);
         CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) {
             if (!rule->pending) {
-                ofproto_rule_delete__(ofproto, rule);
+                ofproto_rule_delete__(ofproto, rule, OFPRR_DELETE);
             }
         }
     }
@@ -1972,6 +1974,13 @@ alloc_ofp_port(struct ofproto *ofproto, const char *netdev_name)
             if (!last_used_at) {
                 port_idx = ofproto->alloc_port_no;
                 break;
+            } else if ( last_used_at < time_msec() - 60*60*1000) {
+                /* If the port with ofport 'ofproto->alloc_port_no' was deleted
+                 * more than an hour ago, consider it usable. */
+                ofport_remove_usage(ofproto,
+                    u16_to_ofp(ofproto->alloc_port_no));
+                port_idx = ofproto->alloc_port_no;
+                break;
             } else if (last_used_at < lru) {
                 lru = last_used_at;
                 lru_ofport = ofproto->alloc_port_no;
@@ -2254,6 +2263,20 @@ ofport_set_usage(struct ofproto *ofproto, ofp_port_t ofp_port,
                 hash_ofp_port(ofp_port));
 }
 
+static void
+ofport_remove_usage(struct ofproto *ofproto, ofp_port_t ofp_port)
+{
+    struct ofport_usage *usage;
+    HMAP_FOR_EACH_IN_BUCKET (usage, hmap_node, hash_ofp_port(ofp_port),
+                             &ofproto->ofport_usage) {
+        if (usage->ofp_port == ofp_port) {
+            hmap_remove(&ofproto->ofport_usage, &usage->hmap_node);
+            free(usage);
+            break;
+        }
+    }
+}
+
 int
 ofproto_port_get_stats(const struct ofport *port, struct netdev_stats *stats)
 {
@@ -3555,6 +3578,7 @@ flow_stats_ds(struct rule *rule, struct ds *results)
     cls_rule_format(&rule->cr, results);
     ds_put_char(results, ',');
 
+    ds_put_cstr(results, "actions=");
     ofpacts_format(actions->ofpacts, actions->ofpacts_len, results);
 
     ds_put_cstr(results, "\n");
@@ -4299,8 +4323,7 @@ ofproto_rule_expire(struct rule *rule, uint8_t reason)
     ovs_assert(reason == OFPRR_HARD_TIMEOUT || reason == OFPRR_IDLE_TIMEOUT
                || reason == OFPRR_DELETE || reason == OFPRR_GROUP_DELETE);
 
-    ofproto_rule_send_removed(rule, reason);
-    ofproto_rule_delete__(ofproto, rule);
+    ofproto_rule_delete__(ofproto, rule, reason);
 }
 
 /* Reduces '*timeout' to no more than 'max'.  A value of zero in either case