netdev-bsd: Correct pointer use after refactoring.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index a42625b..280fd57 100644 (file)
@@ -218,6 +218,17 @@ struct action_xlate_ctx {
      * this flow when actions change header fields. */
     struct flow flow;
 
+    /* Flow at the last commit. */
+    struct flow base_flow;
+
+    /* Tunnel IP destination address as received.  This is stored separately
+     * as the base_flow.tunnel is cleared on init to reflect the datapath
+     * behavior.  Used to make sure not to send tunneled output to ourselves,
+     * which might lead to an infinite loop.  This could happen easily
+     * if a tunnel is marked as 'ip_remote=flow', and the flow does not
+     * actually set the tun_dst field. */
+    ovs_be32 orig_tunnel_ip_dst;
+
     /* stack for the push and pop actions.
      * Each stack element is of the type "union mf_subvalue". */
     struct ofpbuf stack;
@@ -283,7 +294,6 @@ struct action_xlate_ctx {
 
     int recurse;                /* Recursion level, via xlate_table_action. */
     bool max_resubmit_trigger;  /* Recursed too deeply during translation. */
-    struct flow base_flow;      /* Flow at the last commit. */
     uint32_t orig_skb_priority; /* Priority when packet arrived. */
     uint8_t table_id;           /* OpenFlow table ID where flow was found. */
     uint32_t sflow_n_outputs;   /* Number of output ports. */
@@ -1963,7 +1973,7 @@ set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
 
             ofproto = ofproto_dpif_cast(ofport->up.ofproto);
             ofproto->backer->need_revalidate = REV_RECONFIGURE;
-            ofport->cfm = cfm_create(netdev_get_name(ofport->up.netdev));
+            ofport->cfm = cfm_create(ofport->up.netdev);
         }
 
         if (cfm_configure(ofport->cfm, s)) {
@@ -2462,7 +2472,7 @@ bundle_del_port(struct ofport_dpif *port)
 }
 
 static bool
-bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
+bundle_add_port(struct ofbundle *bundle, uint16_t ofp_port,
                 struct lacp_slave_settings *lacp)
 {
     struct ofport_dpif *port;
@@ -3374,23 +3384,6 @@ port_get_stats(const struct ofport *ofport_, struct netdev_stats *stats)
     return error;
 }
 
-/* Account packets for LOCAL port. */
-static void
-ofproto_update_local_port_stats(const struct ofproto *ofproto_,
-                                size_t tx_size, size_t rx_size)
-{
-    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
-
-    if (rx_size) {
-        ofproto->stats.rx_packets++;
-        ofproto->stats.rx_bytes += rx_size;
-    }
-    if (tx_size) {
-        ofproto->stats.tx_packets++;
-        ofproto->stats.tx_bytes += tx_size;
-    }
-}
-
 struct port_dump_state {
     uint32_t bucket;
     uint32_t offset;
@@ -3693,8 +3686,8 @@ handle_flow_miss_without_facet(struct flow_miss *miss,
         dpif_flow_stats_extract(&miss->flow, packet, now, &stats);
         rule_credit_stats(rule, &stats);
 
-        action_xlate_ctx_init(&ctx, ofproto, &miss->flow,
-                              &miss->initial_vals, rule, 0, packet);
+        action_xlate_ctx_init(&ctx, ofproto, &miss->flow, &miss->initial_vals,
+                              rule, stats.tcp_flags, packet);
         ctx.resubmit_stats = &stats;
         xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len,
                       &odp_actions);
@@ -3921,51 +3914,41 @@ ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
         *odp_in_port = flow->in_port;
     }
 
-    if (tnl_port_should_receive(flow)) {
-        const struct ofport *ofport = tnl_port_receive(flow);
-        if (!ofport) {
-            flow->in_port = OFPP_NONE;
-            goto exit;
-        }
-        flow->in_port = ofport->ofp_port;
-        port = ofport_dpif_cast(ofport);
+    port = (tnl_port_should_receive(flow)
+            ? ofport_dpif_cast(tnl_port_receive(flow))
+            : odp_port_to_ofport(backer, flow->in_port));
+    flow->in_port = port ? port->up.ofp_port : OFPP_NONE;
+    if (!port) {
+        goto exit;
+    }
 
-        /* XXX: Since the tunnel module is not scoped per backer, it's
-         * theoretically possible that we'll receive an ofport belonging to an
-         * entirely different datapath.  In practice, this can't happen because
-         * no platforms has two separate datapaths which each support
-         * tunneling. */
-        ovs_assert(ofproto_dpif_cast(port->up.ofproto)->backer == backer);
-    } else {
-        port = odp_port_to_ofport(backer, flow->in_port);
-        if (!port) {
-            flow->in_port = OFPP_NONE;
-            goto exit;
-        }
+    /* XXX: Since the tunnel module is not scoped per backer, for a tunnel port
+     * it's theoretically possible that we'll receive an ofport belonging to an
+     * entirely different datapath.  In practice, this can't happen because no
+     * platforms has two separate datapaths which each support tunneling. */
+    ovs_assert(ofproto_dpif_cast(port->up.ofproto)->backer == backer);
 
-        flow->in_port = port->up.ofp_port;
-        if (vsp_adjust_flow(ofproto_dpif_cast(port->up.ofproto), flow)) {
-            if (packet) {
-                /* Make the packet resemble the flow, so that it gets sent to
-                 * an OpenFlow controller properly, so that it looks correct
-                 * for sFlow, and so that flow_extract() will get the correct
-                 * vlan_tci if it is called on 'packet'.
-                 *
-                 * The allocated space inside 'packet' probably also contains
-                 * 'key', that is, both 'packet' and 'key' are probably part of
-                 * a struct dpif_upcall (see the large comment on that
-                 * structure definition), so pushing data on 'packet' is in
-                 * general not a good idea since it could overwrite 'key' or
-                 * free it as a side effect.  However, it's OK in this special
-                 * case because we know that 'packet' is inside a Netlink
-                 * attribute: pushing 4 bytes will just overwrite the 4-byte
-                 * "struct nlattr", which is fine since we don't need that
-                 * header anymore. */
-                eth_push_vlan(packet, flow->vlan_tci);
-            }
-            /* We can't reproduce 'key' from 'flow'. */
-            fitness = fitness == ODP_FIT_PERFECT ? ODP_FIT_TOO_MUCH : fitness;
-        }
+    if (vsp_adjust_flow(ofproto_dpif_cast(port->up.ofproto), flow)) {
+        if (packet) {
+            /* Make the packet resemble the flow, so that it gets sent to
+             * an OpenFlow controller properly, so that it looks correct
+             * for sFlow, and so that flow_extract() will get the correct
+             * vlan_tci if it is called on 'packet'.
+             *
+             * The allocated space inside 'packet' probably also contains
+             * 'key', that is, both 'packet' and 'key' are probably part of
+             * a struct dpif_upcall (see the large comment on that
+             * structure definition), so pushing data on 'packet' is in
+             * general not a good idea since it could overwrite 'key' or
+             * free it as a side effect.  However, it's OK in this special
+             * case because we know that 'packet' is inside a Netlink
+             * attribute: pushing 4 bytes will just overwrite the 4-byte
+             * "struct nlattr", which is fine since we don't need that
+             * header anymore. */
+            eth_push_vlan(packet, flow->vlan_tci);
+        }
+        /* We can't reproduce 'key' from 'flow'. */
+        fitness = fitness == ODP_FIT_PERFECT ? ODP_FIT_TOO_MUCH : fitness;
     }
     error = 0;
 
@@ -4861,9 +4844,6 @@ facet_flush_stats(struct facet *facet)
         netflow_expire(ofproto->netflow, &facet->nf_flow, &expired);
     }
 
-    facet->rule->packet_count += facet->packet_count;
-    facet->rule->byte_count += facet->byte_count;
-
     /* Reset counters to prevent double counting if 'facet' ever gets
      * reinstalled. */
     facet_reset_counters(facet);
@@ -5245,6 +5225,7 @@ facet_push_stats(struct facet *facet)
         facet->prev_byte_count = facet->byte_count;
         facet->prev_used = facet->used;
 
+        rule_credit_stats(facet->rule, &stats);
         flow_push_stats(facet, &stats);
 
         update_mirror_stats(ofproto_dpif_cast(facet->rule->up.ofproto),
@@ -5762,7 +5743,6 @@ static void
 rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes)
 {
     struct rule_dpif *rule = rule_dpif_cast(rule_);
-    struct facet *facet;
 
     /* push_all_stats() can handle flow misses which, when using the learn
      * action, can cause rules to be added and deleted.  This can corrupt our
@@ -5774,14 +5754,6 @@ rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes)
      * in facets.  This counts, for example, facets that have expired. */
     *packets = rule->packet_count;
     *bytes = rule->byte_count;
-
-    /* Add any statistics that are tracked by facets.  This includes
-     * statistical data recently updated by ofproto_update_stats() as well as
-     * stats for packets that were executed "by hand" via dpif_execute(). */
-    LIST_FOR_EACH (facet, list_node, &rule->facets) {
-        *packets += facet->packet_count;
-        *bytes += facet->byte_count;
-    }
 }
 
 static void
@@ -5834,69 +5806,33 @@ rule_modify_actions(struct rule *rule_)
 static int
 send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
 {
-    const struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
     uint64_t odp_actions_stub[1024 / 8];
     struct ofpbuf key, odp_actions;
+    struct dpif_flow_stats stats;
     struct odputil_keybuf keybuf;
-    uint32_t odp_port;
+    struct ofpact_output output;
+    struct action_xlate_ctx ctx;
     struct flow flow;
     int error;
 
-    flow_extract(packet, 0, 0, NULL, OFPP_LOCAL, &flow);
-    if (netdev_vport_is_patch(ofport->up.netdev)) {
-        struct ofproto_dpif *peer_ofproto;
-        struct dpif_flow_stats stats;
-        struct ofport_dpif *peer;
-        struct rule_dpif *rule;
-
-        peer = ofport_get_peer(ofport);
-        if (!peer) {
-            return ENODEV;
-        }
-
-        dpif_flow_stats_extract(&flow, packet, time_msec(), &stats);
-        netdev_vport_inc_tx(ofport->up.netdev, &stats);
-        netdev_vport_inc_rx(peer->up.netdev, &stats);
-
-        flow.in_port = peer->up.ofp_port;
-        peer_ofproto = ofproto_dpif_cast(peer->up.ofproto);
-        rule = rule_dpif_lookup(peer_ofproto, &flow);
-        rule_dpif_execute(rule, &flow, packet);
-
-        return 0;
-    }
-
     ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
+    ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
 
-    if (ofport->tnl_port) {
-        struct dpif_flow_stats stats;
-
-        odp_port = tnl_port_send(ofport->tnl_port, &flow);
-        if (odp_port == OVSP_NONE) {
-            return ENODEV;
-        }
-
-        dpif_flow_stats_extract(&flow, packet, time_msec(), &stats);
-        netdev_vport_inc_tx(ofport->up.netdev, &stats);
-        odp_put_tunnel_action(&flow.tunnel, &odp_actions);
-        odp_put_skb_mark_action(flow.skb_mark, &odp_actions);
-    } else {
-        odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
-                                          flow.vlan_tci);
-        if (odp_port != ofport->odp_port) {
-            eth_pop_vlan(packet);
-            flow.vlan_tci = htons(0);
-        }
-    }
+    /* Use OFPP_NONE as the in_port to avoid special packet processing. */
+    flow_extract(packet, 0, 0, NULL, OFPP_NONE, &flow);
+    odp_flow_key_from_flow(&key, &flow, ofp_port_to_odp_port(ofproto,
+                                                             OFPP_LOCAL));
+    dpif_flow_stats_extract(&flow, packet, time_msec(), &stats);
 
-    ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
-    odp_flow_key_from_flow(&key, &flow,
-                           ofp_port_to_odp_port(ofproto, flow.in_port));
+    ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output);
+    output.port = ofport->up.ofp_port;
+    output.max_len = 0;
 
-    compose_sflow_action(ofproto, &odp_actions, &flow, odp_port);
-    compose_ipfix_action(ofproto, &odp_actions, &flow);
+    action_xlate_ctx_init(&ctx, ofproto, &flow, NULL, NULL, 0, packet);
+    ctx.resubmit_stats = &stats;
+    xlate_actions(&ctx, &output.ofpact, sizeof output, &odp_actions);
 
-    nl_msg_put_u32(&odp_actions, OVS_ACTION_ATTR_OUTPUT, odp_port);
     error = dpif_execute(ofproto->backer->dpif,
                          key.data, key.size,
                          odp_actions.data, odp_actions.size,
@@ -5904,10 +5840,13 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
     ofpbuf_uninit(&odp_actions);
 
     if (error) {
-        VLOG_WARN_RL(&rl, "%s: failed to send packet on port %"PRIu32" (%s)",
-                     ofproto->up.name, odp_port, strerror(error));
+        VLOG_WARN_RL(&rl, "%s: failed to send packet on port %s (%s)",
+                     ofproto->up.name, netdev_get_name(ofport->up.netdev),
+                     strerror(error));
     }
-    ofproto_update_local_port_stats(ofport->up.ofproto, packet->size, 0);
+
+    ofproto->stats.tx_packets++;
+    ofproto->stats.tx_bytes += packet->size;
     return error;
 }
 \f
@@ -6231,7 +6170,10 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
             xlate_report(ctx, "Tunneling decided against output");
             goto out; /* restore flow_nw_tos */
         }
-
+        if (ctx->flow.tunnel.ip_dst == ctx->orig_tunnel_ip_dst) {
+            xlate_report(ctx, "Not tunneling to our own address");
+            goto out; /* restore flow_nw_tos */
+        }
         if (ctx->resubmit_stats) {
             netdev_vport_inc_tx(ofport->up.netdev, ctx->resubmit_stats);
         }
@@ -7096,7 +7038,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
     ctx->flow = *flow;
     ctx->base_flow = ctx->flow;
     memset(&ctx->base_flow.tunnel, 0, sizeof ctx->base_flow.tunnel);
-    ctx->base_flow.vlan_tci = initial_vals->vlan_tci;
+    ctx->orig_tunnel_ip_dst = flow->tunnel.ip_dst;
     ctx->rule = rule;
     ctx->packet = packet;
     ctx->may_learn = packet != NULL;
@@ -7104,6 +7046,10 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
     ctx->resubmit_hook = NULL;
     ctx->report_hook = NULL;
     ctx->resubmit_stats = NULL;
+
+    if (initial_vals) {
+        ctx->base_flow.vlan_tci = initial_vals->vlan_tci;
+    }
 }
 
 /* Translates the 'ofpacts_len' bytes of "struct ofpacts" starting at 'ofpacts'
@@ -8182,7 +8128,7 @@ static void
 ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
                       void *aux OVS_UNUSED)
 {
-    const char *dpname = argv[1];
+    const struct dpif_backer *backer;
     struct ofproto_dpif *ofproto;
     struct ofpbuf odp_key;
     struct ofpbuf *packet;
@@ -8192,101 +8138,102 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
     char *s;
 
     packet = NULL;
-    ofpbuf_init(&odp_key, 0);
+    backer = NULL;
     ds_init(&result);
+    ofpbuf_init(&odp_key, 0);
 
-    ofproto = ofproto_dpif_lookup(dpname);
-    if (!ofproto) {
-        unixctl_command_reply_error(conn, "Unknown ofproto (use ofproto/list "
-                                    "for help)");
-        goto exit;
+    /* Handle "-generate" or a hex string as the last argument. */
+    if (!strcmp(argv[argc - 1], "-generate")) {
+        packet = ofpbuf_new(0);
+        argc--;
+    } else {
+        const char *error = eth_from_hex(argv[argc - 1], &packet);
+        if (!error) {
+            argc--;
+        } else if (argc == 4) {
+            /* The 3-argument form must end in "-generate' or a hex string. */
+            unixctl_command_reply_error(conn, error);
+            goto exit;
+        }
     }
-    if (argc == 3 || (argc == 4 && !strcmp(argv[3], "-generate"))) {
-        /* ofproto/trace dpname flow [-generate] */
-        const char *flow_s = argv[2];
-        const char *generate_s = argv[3];
-
-        /* Allow 'flow_s' to be either a datapath flow or an OpenFlow-like
-         * flow.  We guess which type it is based on whether 'flow_s' contains
-         * an '(', since a datapath flow always contains '(') but an
-         * OpenFlow-like flow should not (in fact it's allowed but I believe
-         * that's not documented anywhere).
-         *
-         * An alternative would be to try to parse 'flow_s' both ways, but then
-         * it would be tricky giving a sensible error message.  After all, do
-         * you just say "syntax error" or do you present both error messages?
-         * Both choices seem lousy. */
-        if (strchr(flow_s, '(')) {
-            int error;
 
-            /* Convert string to datapath key. */
-            ofpbuf_init(&odp_key, 0);
-            error = odp_flow_key_from_string(flow_s, NULL, &odp_key);
-            if (error) {
-                unixctl_command_reply_error(conn, "Bad flow syntax");
-                goto exit;
+    /* Parse the flow and determine whether a datapath or
+     * bridge is specified. If function odp_flow_key_from_string()
+     * returns 0, the flow is a odp_flow. If function
+     * parse_ofp_exact_flow() returns 0, the flow is a br_flow. */
+    if (!odp_flow_key_from_string(argv[argc - 1], NULL, &odp_key)) {
+        /* If the odp_flow is the second argument,
+         * the datapath name is the first argument. */
+        if (argc == 3) {
+            const char *dp_type;
+            if (!strncmp(argv[1], "ovs-", 4)) {
+                dp_type = argv[1] + 4;
+            } else {
+                dp_type = argv[1];
             }
-
-            /* The user might have specified the wrong ofproto but within the
-             * same backer.  That's OK, ofproto_receive() can find the right
-             * one for us. */
-            if (ofproto_receive(ofproto->backer, NULL, odp_key.data,
-                                odp_key.size, &flow, NULL, &ofproto, NULL,
-                                &initial_vals)) {
-                unixctl_command_reply_error(conn, "Invalid flow");
+            backer = shash_find_data(&all_dpif_backers, dp_type);
+            if (!backer) {
+                unixctl_command_reply_error(conn, "Cannot find datapath "
+                               "of this name");
                 goto exit;
             }
-            ds_put_format(&result, "Bridge: %s\n", ofproto->up.name);
         } else {
-            char *error_s;
-
-            error_s = parse_ofp_exact_flow(&flow, argv[2]);
-            if (error_s) {
-                unixctl_command_reply_error(conn, error_s);
-                free(error_s);
+            /* No datapath name specified, so there should be only one
+             * datapath. */
+            struct shash_node *node;
+            if (shash_count(&all_dpif_backers) != 1) {
+                unixctl_command_reply_error(conn, "Must specify datapath "
+                         "name, there is more than one type of datapath");
                 goto exit;
             }
-
-            initial_vals.vlan_tci = flow.vlan_tci;
+            node = shash_first(&all_dpif_backers);
+            backer = node->data;
         }
 
-        /* Generate a packet, if requested. */
-        if (generate_s) {
-            packet = ofpbuf_new(0);
-            flow_compose(packet, &flow);
+        /* Extract the ofproto_dpif object from the ofproto_receive()
+         * function. */
+        if (ofproto_receive(backer, NULL, odp_key.data,
+                            odp_key.size, &flow, NULL, &ofproto, NULL,
+                            &initial_vals)) {
+            unixctl_command_reply_error(conn, "Invalid datapath flow");
+            goto exit;
         }
-    } else if (argc == 7) {
-        /* ofproto/trace dpname priority tun_id in_port mark packet */
-        const char *priority_s = argv[2];
-        const char *tun_id_s = argv[3];
-        const char *in_port_s = argv[4];
-        const char *mark_s = argv[5];
-        const char *packet_s = argv[6];
-        uint32_t in_port = atoi(in_port_s);
-        ovs_be64 tun_id = htonll(strtoull(tun_id_s, NULL, 0));
-        uint32_t priority = atoi(priority_s);
-        uint32_t mark = atoi(mark_s);
-        const char *msg;
-
-        msg = eth_from_hex(packet_s, &packet);
-        if (msg) {
-            unixctl_command_reply_error(conn, msg);
+        ds_put_format(&result, "Bridge: %s\n", ofproto->up.name);
+    } else if (!parse_ofp_exact_flow(&flow, argv[argc - 1])) {
+        if (argc != 3) {
+            unixctl_command_reply_error(conn, "Must specify bridge name");
             goto exit;
         }
 
-        ds_put_cstr(&result, "Packet: ");
-        s = ofp_packet_to_string(packet->data, packet->size);
-        ds_put_cstr(&result, s);
-        free(s);
-
-        flow_extract(packet, priority, mark, NULL, in_port, &flow);
-        flow.tunnel.tun_id = tun_id;
+        ofproto = ofproto_dpif_lookup(argv[1]);
+        if (!ofproto) {
+            unixctl_command_reply_error(conn, "Unknown bridge name");
+            goto exit;
+        }
         initial_vals.vlan_tci = flow.vlan_tci;
     } else {
-        unixctl_command_reply_error(conn, "Bad command syntax");
+        unixctl_command_reply_error(conn, "Bad flow syntax");
         goto exit;
     }
 
+    /* Generate a packet, if requested. */
+    if (packet) {
+        if (!packet->size) {
+            flow_compose(packet, &flow);
+        } else {
+            ds_put_cstr(&result, "Packet: ");
+            s = ofp_packet_to_string(packet->data, packet->size);
+            ds_put_cstr(&result, s);
+            free(s);
+
+            /* Use the metadata from the flow and the packet argument
+             * to reconstruct the flow. */
+            flow_extract(packet, flow.skb_priority, flow.skb_mark, NULL,
+                         flow.in_port, &flow);
+            initial_vals.vlan_tci = flow.vlan_tci;
+        }
+    }
+
     ofproto_trace(ofproto, &flow, packet, &initial_vals, &result);
     unixctl_command_reply(conn, ds_cstr(&result));
 
@@ -8715,8 +8662,8 @@ ofproto_dpif_unixctl_init(void)
 
     unixctl_command_register(
         "ofproto/trace",
-        "bridge {priority tun_id in_port mark packet | odp_flow [-generate]}",
-        2, 6, ofproto_unixctl_trace, NULL);
+        "[dp_name]|bridge odp_flow|br_flow [-generate|packet]",
+        1, 3, 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,