X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=1b6a17a22183c861a7621aa22addfd1f220e2d2d;hb=50aa28fdbf2df9d81d663dc6442ab620f912a39e;hp=fea854ab4af5e67fdef3c03e29d738f1609c67db;hpb=79e15b78532f770ed14d91714def962b6b5c3f16;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index fea854ab4..1b6a17a22 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -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. */ @@ -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; @@ -3676,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); @@ -4834,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); @@ -5218,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), @@ -5735,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 @@ -5747,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 @@ -5810,66 +5809,30 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) 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, @@ -5877,8 +5840,9 @@ 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->stats.tx_packets++; @@ -6206,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); } @@ -7071,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; @@ -7079,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' @@ -8157,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; @@ -8167,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)); @@ -8690,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,