vswitchd: Always configure a default queue for QoS.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index a6087bf..1fe5da6 100644 (file)
@@ -76,8 +76,6 @@ struct ofproto_dpif;
 struct rule_dpif {
     struct rule up;
 
-    long long int used;         /* Time last used; time created if not used. */
-
     /* These statistics:
      *
      *   - Do include packets and bytes from facets that have been deleted or
@@ -107,7 +105,7 @@ static struct rule_dpif *rule_dpif_cast(const struct rule *rule)
 static struct rule_dpif *rule_dpif_lookup(struct ofproto_dpif *,
                                           const struct flow *, uint8_t table);
 
-static void flow_push_stats(const struct rule_dpif *, const struct flow *,
+static void flow_push_stats(struct rule_dpif *, const struct flow *,
                             uint64_t packets, uint64_t bytes,
                             long long int used);
 
@@ -215,8 +213,13 @@ struct action_xlate_ctx {
      * we are just revalidating. */
     bool may_learn;
 
-    /* Cookie of the currently matching rule, or 0. */
-    ovs_be64 cookie;
+    /* The rule that we are currently translating, or NULL. */
+    struct rule_dpif *rule;
+
+    /* Union of the set of TCP flags seen so far in this flow.  (Used only by
+     * NXAST_FIN_TIMEOUT.  Set to zero to avoid updating updating rules'
+     * timeouts.) */
+    uint8_t tcp_flags;
 
     /* If nonnull, called just before executing a resubmit action.
      *
@@ -233,6 +236,7 @@ struct action_xlate_ctx {
                                  * be reassessed for every packet. */
     bool has_learn;             /* Actions include NXAST_LEARN? */
     bool has_normal;            /* Actions output to OFPP_NORMAL? */
+    bool has_fin_timeout;       /* Actions include NXAST_FIN_TIMEOUT? */
     uint16_t nf_output_iface;   /* Output interface index for NetFlow. */
     mirror_mask_t mirrors;      /* Bitmap of associated mirrors. */
 
@@ -251,8 +255,8 @@ struct action_xlate_ctx {
 
 static void action_xlate_ctx_init(struct action_xlate_ctx *,
                                   struct ofproto_dpif *, const struct flow *,
-                                  ovs_be16 initial_tci, ovs_be64 cookie,
-                                  const struct ofpbuf *);
+                                  ovs_be16 initial_tci, struct rule_dpif *,
+                                  uint8_t tcp_flags, const struct ofpbuf *);
 static struct ofpbuf *xlate_actions(struct action_xlate_ctx *,
                                     const union ofp_action *in, size_t n_in);
 
@@ -306,6 +310,7 @@ struct facet {
     /* Accounting. */
     uint64_t accounted_bytes;    /* Bytes processed by facet_account(). */
     struct netflow_flow nf_flow; /* Per-flow NetFlow tracking data. */
+    uint8_t tcp_flags;           /* TCP flags seen for this 'rule'. */
 
     /* Properties of datapath actions.
      *
@@ -316,6 +321,7 @@ struct facet {
     bool may_install;            /* Reassess actions for every packet? */
     bool has_learn;              /* Actions include NXAST_LEARN? */
     bool has_normal;             /* Actions output to OFPP_NORMAL? */
+    bool has_fin_timeout;        /* Actions include NXAST_FIN_TIMEOUT? */
     tag_type tags;               /* Tags that would require revalidation. */
     mirror_mask_t mirrors;       /* Bitmap of dependent mirrors. */
 };
@@ -650,7 +656,7 @@ construct(struct ofproto *ofproto_)
     ofproto->sflow = NULL;
     ofproto->stp = NULL;
     hmap_init(&ofproto->bundles);
-    ofproto->ml = mac_learning_create();
+    ofproto->ml = mac_learning_create(MAC_ENTRY_DEFAULT_IDLE_TIME);
     for (i = 0; i < MAX_MIRRORS; i++) {
         ofproto->mirrors[i] = NULL;
     }
@@ -2152,6 +2158,13 @@ forward_bpdu_changed(struct ofproto *ofproto_)
     /* Revalidate cached flows whenever forward_bpdu option changes. */
     ofproto->need_revalidate = true;
 }
+
+static void
+set_mac_idle_time(struct ofproto *ofproto_, unsigned int idle_time)
+{
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+    mac_learning_set_idle_time(ofproto->ml, idle_time);
+}
 \f
 /* Ports. */
 
@@ -2949,6 +2962,8 @@ update_stats(struct ofproto_dpif *p)
             subfacet->dp_packet_count = stats->n_packets;
             subfacet->dp_byte_count = stats->n_bytes;
 
+            facet->tcp_flags |= stats->tcp_flags;
+
             subfacet_update_time(subfacet, stats->used);
             facet_account(facet);
             facet_push_stats(facet);
@@ -3088,7 +3103,7 @@ rule_expire(struct rule_dpif *rule)
         && now > rule->up.modified + rule->up.hard_timeout * 1000) {
         reason = OFPRR_HARD_TIMEOUT;
     } else if (rule->up.idle_timeout && list_is_empty(&rule->facets)
-               && now > rule->used + rule->up.idle_timeout * 1000) {
+               && now > rule->up.used + rule->up.idle_timeout * 1000) {
         reason = OFPRR_IDLE_TIMEOUT;
     } else {
         return;
@@ -3220,12 +3235,14 @@ facet_account(struct facet *facet)
     /* Feed information from the active flows back into the learning table to
      * ensure that table is always in sync with what is actually flowing
      * through the datapath. */
-    if (facet->has_learn || facet->has_normal) {
+    if (facet->has_learn || facet->has_normal
+        || (facet->has_fin_timeout
+            && facet->tcp_flags & (TCP_FIN | TCP_RST))) {
         struct action_xlate_ctx ctx;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
                               facet->flow.vlan_tci,
-                              facet->rule->up.flow_cookie, NULL);
+                              facet->rule, facet->tcp_flags, NULL);
         ctx.may_learn = true;
         ofpbuf_delete(xlate_actions(&ctx, facet->rule->up.actions,
                                     facet->rule->up.n_actions));
@@ -3319,6 +3336,7 @@ facet_flush_stats(struct facet *facet)
     facet_reset_counters(facet);
 
     netflow_flow_clear(&facet->nf_flow);
+    facet->tcp_flags = 0;
 }
 
 /* Searches 'ofproto''s table of facets for one exactly equal to 'flow'.
@@ -3415,8 +3433,7 @@ facet_check_consistency(struct facet *facet)
         bool should_install;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
-                              subfacet->initial_tci, rule->up.flow_cookie,
-                              NULL);
+                              subfacet->initial_tci, rule, 0, NULL);
         odp_actions = xlate_actions(&ctx, rule->up.actions,
                                     rule->up.n_actions);
 
@@ -3535,8 +3552,7 @@ facet_revalidate(struct facet *facet)
         bool should_install;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
-                              subfacet->initial_tci, new_rule->up.flow_cookie,
-                              NULL);
+                              subfacet->initial_tci, new_rule, 0, NULL);
         odp_actions = xlate_actions(&ctx, new_rule->up.actions,
                                     new_rule->up.n_actions);
         actions_changed = (subfacet->actions_len != odp_actions->size
@@ -3578,6 +3594,7 @@ facet_revalidate(struct facet *facet)
     facet->may_install = ctx.may_set_up_flow;
     facet->has_learn = ctx.has_learn;
     facet->has_normal = ctx.has_normal;
+    facet->has_fin_timeout = ctx.has_fin_timeout;
     facet->mirrors = ctx.mirrors;
     if (new_actions) {
         i = 0;
@@ -3611,9 +3628,7 @@ facet_update_time(struct facet *facet, long long int used)
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
     if (used > facet->used) {
         facet->used = used;
-        if (used > facet->rule->used) {
-            facet->rule->used = used;
-        }
+        ofproto_rule_update_used(&facet->rule->up, used);
         netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, used);
     }
 }
@@ -3668,14 +3683,14 @@ push_resubmit(struct action_xlate_ctx *ctx, struct rule_dpif *rule)
     if (rule) {
         rule->packet_count += push->packets;
         rule->byte_count += push->bytes;
-        rule->used = MAX(push->used, rule->used);
+        ofproto_rule_update_used(&rule->up, push->used);
     }
 }
 
 /* Pushes flow statistics to the rules which 'flow' resubmits into given
  * 'rule''s actions and mirrors. */
 static void
-flow_push_stats(const struct rule_dpif *rule,
+flow_push_stats(struct rule_dpif *rule,
                 const struct flow *flow, uint64_t packets, uint64_t bytes,
                 long long int used)
 {
@@ -3686,8 +3701,10 @@ flow_push_stats(const struct rule_dpif *rule,
     push.bytes = bytes;
     push.used = used;
 
-    action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci,
-                          rule->up.flow_cookie, NULL);
+    ofproto_rule_update_used(&rule->up, used);
+
+    action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci, rule,
+                          0, NULL);
     push.ctx.resubmit_hook = push_resubmit;
     ofpbuf_delete(xlate_actions(&push.ctx,
                                 rule->up.actions, rule->up.n_actions));
@@ -3826,18 +3843,19 @@ static void
 subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet)
 {
     struct facet *facet = subfacet->facet;
-    const struct rule_dpif *rule = facet->rule;
+    struct rule_dpif *rule = facet->rule;
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
     struct ofpbuf *odp_actions;
     struct action_xlate_ctx ctx;
 
     action_xlate_ctx_init(&ctx, ofproto, &facet->flow, subfacet->initial_tci,
-                          rule->up.flow_cookie, packet);
+                          rule, 0, packet);
     odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions);
     facet->tags = ctx.tags;
     facet->may_install = ctx.may_set_up_flow;
     facet->has_learn = ctx.has_learn;
     facet->has_normal = ctx.has_normal;
+    facet->has_fin_timeout = ctx.has_fin_timeout;
     facet->nf_flow.output_iface = ctx.nf_output_iface;
     facet->mirrors = ctx.mirrors;
 
@@ -3957,6 +3975,7 @@ subfacet_update_stats(struct subfacet *subfacet,
         subfacet_update_time(subfacet, stats->used);
         facet->packet_count += stats->n_packets;
         facet->byte_count += stats->n_bytes;
+        facet->tcp_flags |= stats->tcp_flags;
         facet_push_stats(facet);
         netflow_flow_update_flags(&facet->nf_flow, stats->tcp_flags);
     }
@@ -4034,7 +4053,6 @@ rule_construct(struct rule *rule_)
         return error;
     }
 
-    rule->used = rule->up.created;
     rule->packet_count = 0;
     rule->byte_count = 0;
 
@@ -4113,15 +4131,14 @@ rule_execute(struct rule *rule_, const struct flow *flow,
     size_t size;
 
     action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci,
-                          rule->up.flow_cookie, packet);
+                          rule, packet_get_tcp_flags(packet, flow), packet);
     odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions);
     size = packet->size;
     if (execute_odp_actions(ofproto, flow, odp_actions->data,
                             odp_actions->size, packet)) {
-        rule->used = time_msec();
         rule->packet_count++;
         rule->byte_count += size;
-        flow_push_stats(rule, flow, 1, size, rule->used);
+        flow_push_stats(rule, flow, 1, size, time_msec());
     }
     ofpbuf_delete(odp_actions);
 
@@ -4383,12 +4400,12 @@ xlate_table_action(struct action_xlate_ctx *ctx,
         }
 
         if (rule) {
-            ovs_be64 old_cookie = ctx->cookie;
+            struct rule_dpif *old_rule = ctx->rule;
 
             ctx->recurse++;
-            ctx->cookie = rule->up.flow_cookie;
+            ctx->rule = rule;
             do_xlate_actions(rule->up.actions, rule->up.n_actions, ctx);
-            ctx->cookie = old_cookie;
+            ctx->rule = old_rule;
             ctx->recurse--;
         }
 
@@ -4487,7 +4504,7 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
     pin.packet_len = packet->size;
     pin.reason = reason;
     pin.table_id = ctx->table_id;
-    pin.cookie = ctx->cookie;
+    pin.cookie = ctx->rule ? ctx->rule->up.flow_cookie : 0;
 
     pin.buffer_id = 0;
     pin.send_len = len;
@@ -4544,11 +4561,9 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
     case OFPP_CONTROLLER:
         execute_controller_action(ctx, max_len, OFPR_ACTION);
         break;
-    case OFPP_LOCAL:
-        compose_output_action(ctx, OFPP_LOCAL);
-        break;
     case OFPP_NONE:
         break;
+    case OFPP_LOCAL:
     default:
         if (port != ctx->flow.in_port) {
             compose_output_action(ctx, port);
@@ -4710,6 +4725,28 @@ xlate_learn_action(struct action_xlate_ctx *ctx,
     free(fm.actions);
 }
 
+/* Reduces '*timeout' to no more than 'max'.  A value of zero in either case
+ * means "infinite". */
+static void
+reduce_timeout(uint16_t max, uint16_t *timeout)
+{
+    if (max && (!*timeout || *timeout > max)) {
+        *timeout = max;
+    }
+}
+
+static void
+xlate_fin_timeout(struct action_xlate_ctx *ctx,
+                  const struct nx_action_fin_timeout *naft)
+{
+    if (ctx->tcp_flags & (TCP_FIN | TCP_RST) && ctx->rule) {
+        struct rule_dpif *rule = ctx->rule;
+
+        reduce_timeout(ntohs(naft->fin_idle_timeout), &rule->up.idle_timeout);
+        reduce_timeout(ntohs(naft->fin_hard_timeout), &rule->up.hard_timeout);
+    }
+}
+
 static bool
 may_receive(const struct ofport_dpif *port, struct action_xlate_ctx *ctx)
 {
@@ -4737,6 +4774,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
 {
     const struct ofport_dpif *port;
     const union ofp_action *ia;
+    bool was_evictable = true;
     size_t left;
 
     port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
@@ -4745,6 +4783,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
         return;
     }
 
+    if (ctx->rule) {
+        /* Don't let the rule we're working on get evicted underneath us. */
+        was_evictable = ctx->rule->up.evictable;
+        ctx->rule->up.evictable = false;
+    }
     OFPUTIL_ACTION_FOR_EACH_UNSAFE (ia, left, in, n_in) {
         const struct ofp_action_dl_addr *oada;
         const struct nx_action_resubmit *nar;
@@ -4909,6 +4952,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
         case OFPUTIL_NXAST_EXIT:
             ctx->exit = true;
             break;
+
+        case OFPUTIL_NXAST_FIN_TIMEOUT:
+            ctx->has_fin_timeout = true;
+            xlate_fin_timeout(ctx, (const struct nx_action_fin_timeout *) ia);
+            break;
         }
     }
 
@@ -4919,22 +4967,26 @@ out:
         ofpbuf_clear(ctx->odp_actions);
         add_sflow_action(ctx);
     }
+    if (ctx->rule) {
+        ctx->rule->up.evictable = was_evictable;
+    }
 }
 
 static void
 action_xlate_ctx_init(struct action_xlate_ctx *ctx,
                       struct ofproto_dpif *ofproto, const struct flow *flow,
-                      ovs_be16 initial_tci, ovs_be64 cookie,
-                      const struct ofpbuf *packet)
+                      ovs_be16 initial_tci, struct rule_dpif *rule,
+                      uint8_t tcp_flags, const struct ofpbuf *packet)
 {
     ctx->ofproto = ofproto;
     ctx->flow = *flow;
     ctx->base_flow = ctx->flow;
     ctx->base_flow.tun_id = 0;
     ctx->base_flow.vlan_tci = initial_tci;
-    ctx->cookie = cookie;
+    ctx->rule = rule;
     ctx->packet = packet;
     ctx->may_learn = packet != NULL;
+    ctx->tcp_flags = tcp_flags;
     ctx->resubmit_hook = NULL;
 }
 
@@ -4952,6 +5004,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
     ctx->may_set_up_flow = true;
     ctx->has_learn = false;
     ctx->has_normal = false;
+    ctx->has_fin_timeout = false;
     ctx->nf_output_iface = NF_OUT_DROP;
     ctx->mirrors = 0;
     ctx->recurse = 0;
@@ -5721,8 +5774,8 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
         ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
         odp_flow_key_from_flow(&key, flow);
 
-        action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci, 0,
-                              packet);
+        action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci, NULL,
+                              packet_get_tcp_flags(packet, flow), packet);
 
         /* Ensure that resubmits in 'ofp_actions' get accounted to their
          * matching rules. */
@@ -5859,7 +5912,8 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
         struct ofbundle *bundle = e->port.p;
         ds_put_format(&ds, "%5d  %4d  "ETH_ADDR_FMT"  %3d\n",
                       ofbundle_get_a_port(bundle)->odp_port,
-                      e->vlan, ETH_ADDR_ARGS(e->mac), mac_entry_age(e));
+                      e->vlan, ETH_ADDR_ARGS(e->mac),
+                      mac_entry_age(ofproto->ml, e));
     }
     unixctl_command_reply(conn, 200, ds_cstr(&ds));
     ds_destroy(&ds);
@@ -6023,11 +6077,13 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
     if (rule) {
         struct ofproto_trace trace;
         struct ofpbuf *odp_actions;
+        uint8_t tcp_flags;
 
+        tcp_flags = packet ? packet_get_tcp_flags(packet, &flow) : 0;
         trace.result = &result;
         trace.flow = flow;
         action_xlate_ctx_init(&trace.ctx, ofproto, &flow, initial_tci,
-                              rule->up.flow_cookie, packet);
+                              rule, tcp_flags, packet);
         trace.ctx.resubmit_hook = trace_resubmit;
         odp_actions = xlate_actions(&trace.ctx,
                                     rule->up.actions, rule->up.n_actions);
@@ -6348,5 +6404,6 @@ const struct ofproto_class ofproto_dpif_class = {
     set_flood_vlans,
     is_mirror_output_bundle,
     forward_bpdu_changed,
+    set_mac_idle_time,
     set_realdev,
 };