ofproto: Optionally flush all learning tables with appctl.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index 97ddfed..9b06df0 100644 (file)
@@ -214,6 +214,9 @@ struct action_xlate_ctx {
      * we are just revalidating. */
     bool may_learn;
 
+    /* Cookie of the currently matching rule, or 0. */
+    ovs_be64 cookie;
+
     /* If nonnull, called just before executing a resubmit action.
      *
      * This is normally null so the client has to set it manually after
@@ -247,7 +250,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, const struct ofpbuf *);
+                                  ovs_be16 initial_tci, ovs_be64 cookie,
+                                  const struct ofpbuf *);
 static struct ofpbuf *xlate_actions(struct action_xlate_ctx *,
                                     const union ofp_action *in, size_t n_in);
 
@@ -2415,6 +2419,10 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, struct ofpbuf *packet,
     pin.packet_len = packet->size;
     pin.total_len = packet->size;
     pin.reason = OFPR_NO_MATCH;
+
+    pin.table_id = 0;
+    pin.cookie = 0;
+
     pin.buffer_id = 0;          /* not yet known */
     pin.send_len = 0;           /* not used for flow table misses */
 
@@ -3196,7 +3204,8 @@ facet_account(struct ofproto_dpif *ofproto, struct facet *facet)
         struct action_xlate_ctx ctx;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
-                              facet->flow.vlan_tci, NULL);
+                              facet->flow.vlan_tci,
+                              facet->rule->up.flow_cookie, NULL);
         ctx.may_learn = true;
         ofpbuf_delete(xlate_actions(&ctx, facet->rule->up.actions,
                                     facet->rule->up.n_actions));
@@ -3385,7 +3394,8 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
         bool should_install;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
-                              subfacet->initial_tci, NULL);
+                              subfacet->initial_tci, new_rule->up.flow_cookie,
+                              NULL);
         odp_actions = xlate_actions(&ctx, new_rule->up.actions,
                                     new_rule->up.n_actions);
         actions_changed = (subfacet->actions_len != odp_actions->size
@@ -3535,7 +3545,8 @@ 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, NULL);
+    action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci,
+                          rule->up.flow_cookie, NULL);
     push.ctx.resubmit_hook = push_resubmit;
     ofpbuf_delete(xlate_actions(&push.ctx,
                                 rule->up.actions, rule->up.n_actions));
@@ -3677,7 +3688,7 @@ subfacet_make_actions(struct ofproto_dpif *p, struct subfacet *subfacet,
     struct action_xlate_ctx ctx;
 
     action_xlate_ctx_init(&ctx, p, &facet->flow, subfacet->initial_tci,
-                          packet);
+                          rule->up.flow_cookie, 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;
@@ -3955,7 +3966,8 @@ rule_execute(struct rule *rule_, const struct flow *flow,
     struct ofpbuf *odp_actions;
     size_t size;
 
-    action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, packet);
+    action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci,
+                          rule->up.flow_cookie, 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,
@@ -4225,8 +4237,12 @@ xlate_table_action(struct action_xlate_ctx *ctx,
         }
 
         if (rule) {
+            ovs_be64 old_cookie = ctx->cookie;
+
             ctx->recurse++;
+            ctx->cookie = rule->up.flow_cookie;
             do_xlate_actions(rule->up.actions, rule->up.n_actions, ctx);
+            ctx->cookie = old_cookie;
             ctx->recurse--;
         }
 
@@ -4323,6 +4339,9 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len)
     pin.packet = packet->data;
     pin.packet_len = packet->size;
     pin.reason = OFPR_ACTION;
+    pin.table_id = ctx->table_id;
+    pin.cookie = ctx->cookie;
+
     pin.buffer_id = 0;
     pin.send_len = len;
     pin.total_len = packet->size;
@@ -4615,8 +4634,11 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
             break;
 
         case OFPUTIL_OFPAT_SET_NW_TOS:
-            ctx->flow.nw_tos &= ~IP_DSCP_MASK;
-            ctx->flow.nw_tos |= ia->nw_tos.nw_tos & IP_DSCP_MASK;
+            /* OpenFlow 1.0 only supports IPv4. */
+            if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) {
+                ctx->flow.nw_tos &= ~IP_DSCP_MASK;
+                ctx->flow.nw_tos |= ia->nw_tos.nw_tos & IP_DSCP_MASK;
+            }
             break;
 
         case OFPUTIL_OFPAT_SET_TP_SRC:
@@ -4728,13 +4750,15 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
 static void
 action_xlate_ctx_init(struct action_xlate_ctx *ctx,
                       struct ofproto_dpif *ofproto, const struct flow *flow,
-                      ovs_be16 initial_tci, const struct ofpbuf *packet)
+                      ovs_be16 initial_tci, ovs_be64 cookie,
+                      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->packet = packet;
     ctx->may_learn = packet != NULL;
     ctx->resubmit_hook = NULL;
@@ -5513,15 +5537,24 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
                              ofproto->max_ports);
     if (!error) {
         struct odputil_keybuf keybuf;
-        struct action_xlate_ctx ctx;
         struct ofpbuf *odp_actions;
+        struct ofproto_push push;
         struct ofpbuf key;
 
         ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
         odp_flow_key_from_flow(&key, flow);
 
-        action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, packet);
-        odp_actions = xlate_actions(&ctx, ofp_actions, n_ofp_actions);
+        action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci, 0,
+                              packet);
+
+        /* Ensure that resubmits in 'ofp_actions' get accounted to their
+         * matching rules. */
+        push.packets = 1;
+        push.bytes = packet->size;
+        push.used = time_msec();
+        push.ctx.resubmit_hook = push_resubmit;
+
+        odp_actions = xlate_actions(&push.ctx, ofp_actions, n_ofp_actions);
         dpif_execute(ofproto->dpif, key.data, key.size,
                      odp_actions->data, odp_actions->size, packet);
         ofpbuf_delete(odp_actions);
@@ -5609,17 +5642,25 @@ ofproto_dpif_lookup(const char *name)
 }
 
 static void
-ofproto_unixctl_fdb_flush(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ofproto_unixctl_fdb_flush(struct unixctl_conn *conn, int argc,
                           const char *argv[], void *aux OVS_UNUSED)
 {
-    const struct ofproto_dpif *ofproto;
+    struct ofproto_dpif *ofproto;
 
-    ofproto = ofproto_dpif_lookup(argv[1]);
-    if (!ofproto) {
-        unixctl_command_reply(conn, 501, "no such bridge");
-        return;
+    if (argc > 1) {
+        ofproto = ofproto_dpif_lookup(argv[1]);
+        if (!ofproto) {
+            unixctl_command_reply(conn, 501, "no such bridge");
+            return;
+        }
+        mac_learning_flush(ofproto->ml);
+        ofproto->need_revalidate = true;
+    } else {
+        HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+            mac_learning_flush(ofproto->ml);
+            ofproto->need_revalidate = true;
+        }
     }
-    mac_learning_flush(ofproto->ml);
 
     unixctl_command_reply(conn, 200, "table successfully flushed");
 }
@@ -5810,7 +5851,8 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
 
         trace.result = &result;
         trace.flow = flow;
-        action_xlate_ctx_init(&trace.ctx, ofproto, &flow, initial_tci, packet);
+        action_xlate_ctx_init(&trace.ctx, ofproto, &flow, initial_tci,
+                              rule->up.flow_cookie, packet);
         trace.ctx.resubmit_hook = trace_resubmit;
         odp_actions = xlate_actions(&trace.ctx,
                                     rule->up.actions, rule->up.n_actions);
@@ -5867,8 +5909,8 @@ ofproto_dpif_unixctl_init(void)
     unixctl_command_register(
         "ofproto/trace",
         "bridge {tun_id in_port packet | odp_flow [-generate]}",
-        2, 4, ofproto_unixctl_trace, NULL);
-    unixctl_command_register("fdb/flush", "bridge", 1, 1,
+        2, 5, ofproto_unixctl_trace, NULL);
+    unixctl_command_register("fdb/flush", "[bridge]", 0, 1,
                              ofproto_unixctl_fdb_flush, NULL);
     unixctl_command_register("fdb/show", "bridge", 1, 1,
                              ofproto_unixctl_fdb_show, NULL);