X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=c7872baf7a3baac5b57542c66e19db8d515cb5df;hb=a4b2e516ffd0aa466f2d0182c89a91ce5d23d9a4;hp=27f9ef4d488763d7137c1394fe9e71d98f9c9fc6;hpb=3394b5b69070b0aef4fc3231ca28bdf09bc0a0d2;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 27f9ef4d..c7872baf 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -93,6 +93,10 @@ COVERAGE_DEFINE(ofproto_update_port); #include "sflow_api.h" +/* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a + * flow translation. */ +#define MAX_RESUBMIT_RECURSION 16 + struct rule; struct ofport { @@ -123,7 +127,7 @@ struct action_xlate_ctx { * * This is normally null so the client has to set it manually after * calling action_xlate_ctx_init(). */ - void (*resubmit_hook)(struct action_xlate_ctx *, const struct rule *); + void (*resubmit_hook)(struct action_xlate_ctx *, struct rule *); /* If true, the speciality of 'flow' should be checked before executing * its actions. If special_cb returns false on 'flow' rendered @@ -226,6 +230,10 @@ struct facet { uint64_t dp_packet_count; /* Last known packet count in the datapath. */ uint64_t dp_byte_count; /* Last known byte count in the datapath. */ + uint64_t rs_packet_count; /* Packets pushed to resubmit children. */ + uint64_t rs_byte_count; /* Bytes pushed to resubmit children. */ + long long int rs_used; /* Used time pushed to resubmit children. */ + /* Number of bytes passed to account_cb. This may include bytes that can * currently obtained from the datapath (thus, it can be greater than * byte_count). */ @@ -261,6 +269,7 @@ static void facet_make_actions(struct ofproto *, struct facet *, const struct ofpbuf *packet); static void facet_update_stats(struct ofproto *, struct facet *, const struct dpif_flow_stats *); +static void facet_push_stats(struct ofproto *, struct facet *); /* ofproto supports two kinds of OpenFlow connections: * @@ -416,6 +425,9 @@ static uint64_t pick_datapath_id(const struct ofproto *); static uint64_t pick_fallback_dpid(void); static int ofproto_expire(struct ofproto *); +static void flow_push_stats(struct ofproto *, const struct rule *, + struct flow *, uint64_t packets, uint64_t bytes, + long long int used); static void handle_upcall(struct ofproto *, struct dpif_upcall *); @@ -1384,9 +1396,15 @@ ofproto_get_ofproto_controller_info(const struct ofproto * ofproto, cinfo->pairs.values[cinfo->pairs.n++] = xstrdup(rconn_get_state(rconn)); - cinfo->pairs.keys[cinfo->pairs.n] = "time_in_state"; - cinfo->pairs.values[cinfo->pairs.n++] = - xasprintf("%u", rconn_get_state_elapsed(rconn)); + if (rconn_is_admitted(rconn)) { + cinfo->pairs.keys[cinfo->pairs.n] = "time_connected"; + cinfo->pairs.values[cinfo->pairs.n++] = + xasprintf("%ld", time_now() - rconn_get_last_connection(rconn)); + } else { + cinfo->pairs.keys[cinfo->pairs.n] = "time_disconnected"; + cinfo->pairs.values[cinfo->pairs.n++] = + xasprintf("%d", rconn_failure_duration(rconn)); + } } } @@ -1514,6 +1532,8 @@ ofproto_flush_flows(struct ofproto *ofproto) * individually since we are about to blow away all the facets with * dpif_flow_flush(). */ facet->installed = false; + facet->dp_packet_count = 0; + facet->dp_byte_count = 0; facet_remove(ofproto, facet); } @@ -1845,6 +1865,7 @@ ofconn_run(struct ofconn *ofconn) char *ofconn_name = ofconn_make_name(p, controller_name); rconn_connect(ofconn->rconn, controller_name, ofconn_name); free(ofconn_name); + free(controller_name); } else { rconn_disconnect(ofconn->rconn); } @@ -2146,12 +2167,10 @@ facet_execute(struct ofproto *ofproto, struct facet *facet, assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in)); flow_extract_stats(&facet->flow, packet, &stats); + stats.used = time_msec(); if (execute_odp_actions(ofproto, &facet->flow, facet->actions, facet->actions_len, packet)) { facet_update_stats(ofproto, facet, &stats); - facet->used = time_msec(); - netflow_flow_update_time(ofproto->netflow, - &facet->nf_flow, facet->used); } } @@ -2203,6 +2222,7 @@ rule_execute(struct ofproto *ofproto, struct rule *rule, uint16_t in_port, rule->used = time_msec(); rule->packet_count++; rule->byte_count += size; + flow_push_stats(ofproto, rule, &flow, 1, size, rule->used); } ofpbuf_delete(odp_actions); } @@ -2387,6 +2407,9 @@ facet_uninstall(struct ofproto *p, struct facet *facet) facet->installed = false; facet->dp_packet_count = 0; facet->dp_byte_count = 0; + } else { + assert(facet->dp_packet_count == 0); + assert(facet->dp_byte_count == 0); } } @@ -2412,6 +2435,7 @@ facet_flush_stats(struct ofproto *ofproto, struct facet *facet) assert(!facet->dp_byte_count); assert(!facet->dp_packet_count); + facet_push_stats(ofproto, facet); facet_account(ofproto, facet, 0); if (ofproto->netflow && !facet_is_controller_flow(facet)) { @@ -2430,6 +2454,8 @@ facet_flush_stats(struct ofproto *ofproto, struct facet *facet) * reinstalled. */ facet->packet_count = 0; facet->byte_count = 0; + facet->rs_packet_count = 0; + facet->rs_byte_count = 0; facet->accounted_bytes = 0; netflow_flow_clear(&facet->nf_flow); @@ -2549,6 +2575,7 @@ facet_revalidate(struct ofproto *ofproto, struct facet *facet) list_push_back(&new_rule->facets, &facet->list_node); facet->rule = new_rule; facet->used = new_rule->created; + facet->rs_used = facet->used; } ofpbuf_delete(odp_actions); @@ -2676,10 +2703,6 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc) return 0; } -/* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a - * flow translation. */ -#define MAX_RESUBMIT_RECURSION 16 - static void do_xlate_actions(const union ofp_action *in, size_t n_in, struct action_xlate_ctx *ctx); @@ -3524,7 +3547,16 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, static bool is_valid_table(uint8_t table_id) { - return table_id == 0 || table_id == 0xff; + if (table_id == 0 || table_id == 0xff) { + return true; + } else { + /* It would probably be better to reply with an error but there doesn't + * seem to be any appropriate value, so that might just be + * confusing. */ + VLOG_WARN_RL(&rl, "controller asked for invalid table %"PRIu8, + table_id); + return false; + } } static int @@ -3843,6 +3875,8 @@ handle_queue_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) return 0; } +/* Updates 'facet''s used time. Caller is responsible for calling + * facet_push_stats() to update the flows which 'facet' resubmits into. */ static void facet_update_time(struct ofproto *ofproto, struct facet *facet, long long int used) @@ -3866,14 +3900,74 @@ static void facet_update_stats(struct ofproto *ofproto, struct facet *facet, const struct dpif_flow_stats *stats) { - if (stats->n_packets) { + if (stats->n_packets || stats->used > facet->used) { facet_update_time(ofproto, facet, stats->used); facet->packet_count += stats->n_packets; facet->byte_count += stats->n_bytes; + facet_push_stats(ofproto, facet); netflow_flow_update_flags(&facet->nf_flow, stats->tcp_flags); } } +static void +facet_push_stats(struct ofproto *ofproto, struct facet *facet) +{ + uint64_t rs_packets, rs_bytes; + + assert(facet->packet_count >= facet->rs_packet_count); + assert(facet->byte_count >= facet->rs_byte_count); + assert(facet->used >= facet->rs_used); + + rs_packets = facet->packet_count - facet->rs_packet_count; + rs_bytes = facet->byte_count - facet->rs_byte_count; + + if (rs_packets || rs_bytes || facet->used > facet->rs_used) { + facet->rs_packet_count = facet->packet_count; + facet->rs_byte_count = facet->byte_count; + facet->rs_used = facet->used; + + flow_push_stats(ofproto, facet->rule, &facet->flow, + rs_packets, rs_bytes, facet->used); + } +} + +struct ofproto_push { + struct action_xlate_ctx ctx; + uint64_t packets; + uint64_t bytes; + long long int used; +}; + +static void +push_resubmit(struct action_xlate_ctx *ctx, struct rule *rule) +{ + struct ofproto_push *push = CONTAINER_OF(ctx, struct ofproto_push, ctx); + + if (rule) { + rule->packet_count += push->packets; + rule->byte_count += push->bytes; + rule->used = MAX(push->used, rule->used); + } +} + +/* Pushes flow statistics to the rules which 'flow' resubmits into given + * 'rule''s actions. */ +static void +flow_push_stats(struct ofproto *ofproto, const struct rule *rule, + struct flow *flow, uint64_t packets, uint64_t bytes, + long long int used) +{ + struct ofproto_push push; + + push.packets = packets; + push.bytes = bytes; + push.used = used; + + action_xlate_ctx_init(&push.ctx, ofproto, flow, NULL); + push.ctx.resubmit_hook = push_resubmit; + ofpbuf_delete(xlate_actions(&push.ctx, rule->actions, rule->n_actions)); +} + /* Implements OFPFC_ADD and the cases for OFPFC_MODIFY and OFPFC_MODIFY_STRICT * in which no matching flow already exists in the flow table. * @@ -4504,6 +4598,15 @@ ofproto_expire(struct ofproto *ofproto) } /* Update 'packet_count', 'byte_count', and 'used' members of installed facets. + * + * This function also pushes statistics updates to rules which each facet + * resubmits into. Generally these statistics will be accurate. However, if a + * facet changes the rule it resubmits into at some time in between + * ofproto_update_stats() runs, it is possible that statistics accrued to the + * old rule will be incorrectly attributed to the new rule. This could be + * avoided by calling ofproto_update_stats() whenever rules are created or + * deleted. However, the performance impact of making so many calls to the + * datapath do not justify the benefit of having perfectly accurate statistics. */ static void ofproto_update_stats(struct ofproto *p) @@ -4550,6 +4653,7 @@ ofproto_update_stats(struct ofproto *p) facet_update_time(p, facet, stats->used); facet_account(p, facet, stats->n_bytes); + facet_push_stats(p, facet); } else { /* There's a flow in the datapath that we know nothing about. * Delete it. */ @@ -5009,7 +5113,7 @@ trace_format_flow(struct ds *result, int level, const char *title, } static void -trace_resubmit(struct action_xlate_ctx *ctx, const struct rule *rule) +trace_resubmit(struct action_xlate_ctx *ctx, struct rule *rule) { struct ofproto_trace *trace = CONTAINER_OF(ctx, struct ofproto_trace, ctx); struct ds *result = trace->result;