X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=b23c79b8a770f356caf4722a27047a53bf3b35b8;hb=f25d0cf3c366;hp=806e56bfac60dc9308f68ed2a06f52b053e003bf;hpb=2be393edd3a94772ef430054dc72ec794c450981;p=cascardo%2Fovs.git diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 806e56bfa..b23c79b8a 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -32,6 +32,7 @@ #include "meta-flow.h" #include "netdev.h" #include "nx-match.h" +#include "ofp-actions.h" #include "ofp-errors.h" #include "ofp-print.h" #include "ofp-util.h" @@ -45,6 +46,7 @@ #include "poll-loop.h" #include "random.h" #include "shash.h" +#include "simap.h" #include "sset.h" #include "timeval.h" #include "unaligned.h" @@ -116,10 +118,9 @@ struct ofoperation { struct hmap_node hmap_node; /* In ofproto's "deletions" hmap. */ struct rule *rule; /* Rule being operated upon. */ enum ofoperation_type type; /* Type of operation. */ - int status; /* -1 if pending, otherwise 0 or error code. */ struct rule *victim; /* OFOPERATION_ADDING: Replaced rule. */ - union ofp_action *actions; /* OFOPERATION_MODIFYING: Replaced actions. */ - int n_actions; /* OFOPERATION_MODIFYING: # of old actions. */ + struct ofpact *ofpacts; /* OFOPERATION_MODIFYING: Replaced actions. */ + size_t ofpacts_len; /* OFOPERATION_MODIFYING: Bytes of ofpacts. */ ovs_be64 flow_cookie; /* Rule's old flow cookie. */ }; @@ -385,6 +386,10 @@ ofproto_create(const char *datapath_name, const char *datapath_type, list_init(&ofproto->pending); ofproto->n_pending = 0; hmap_init(&ofproto->deletions); + ofproto->n_add = ofproto->n_delete = ofproto->n_modify = 0; + ofproto->first_op = ofproto->last_op = LLONG_MIN; + ofproto->next_op_report = LLONG_MAX; + ofproto->op_backoff = LLONG_MIN; ofproto->vlan_bitmap = NULL; ofproto->vlans_changed = false; ofproto->min_mtu = INT_MAX; @@ -1090,6 +1095,43 @@ ofproto_run(struct ofproto *p) NOT_REACHED(); } + if (time_msec() >= p->next_op_report) { + long long int ago = (time_msec() - p->first_op) / 1000; + long long int interval = (p->last_op - p->first_op) / 1000; + struct ds s; + + ds_init(&s); + ds_put_format(&s, "%d flow_mods ", + p->n_add + p->n_delete + p->n_modify); + if (interval == ago) { + ds_put_format(&s, "in the last %lld s", ago); + } else if (interval) { + ds_put_format(&s, "in the %lld s starting %lld s ago", + interval, ago); + } else { + ds_put_format(&s, "%lld s ago", ago); + } + + ds_put_cstr(&s, " ("); + if (p->n_add) { + ds_put_format(&s, "%d adds, ", p->n_add); + } + if (p->n_delete) { + ds_put_format(&s, "%d deletes, ", p->n_delete); + } + if (p->n_modify) { + ds_put_format(&s, "%d modifications, ", p->n_modify); + } + s.length -= 2; + ds_put_char(&s, ')'); + + VLOG_INFO("%s", ds_cstr(&s)); + ds_destroy(&s); + + p->n_add = p->n_delete = p->n_modify = 0; + p->next_op_report = LLONG_MAX; + } + return error; } @@ -1149,6 +1191,31 @@ ofproto_is_alive(const struct ofproto *p) return connmgr_has_controllers(p->connmgr); } +/* Adds some memory usage statistics for 'ofproto' into 'usage', for use with + * memory_report(). */ +void +ofproto_get_memory_usage(const struct ofproto *ofproto, struct simap *usage) +{ + const struct oftable *table; + unsigned int n_rules; + + simap_increase(usage, "ports", hmap_count(&ofproto->ports)); + simap_increase(usage, "ops", + ofproto->n_pending + hmap_count(&ofproto->deletions)); + + n_rules = 0; + OFPROTO_FOR_EACH_TABLE (table, ofproto) { + n_rules += classifier_count(&table->cls); + } + simap_increase(usage, "rules", n_rules); + + if (ofproto->ofproto_class->get_memory_usage) { + ofproto->ofproto_class->get_memory_usage(ofproto, usage); + } + + connmgr_get_memory_usage(ofproto->connmgr, usage); +} + void ofproto_get_ofproto_controller_info(const struct ofproto *ofproto, struct shash *info) @@ -1312,27 +1379,28 @@ ofproto_port_del(struct ofproto *ofproto, uint16_t ofp_port) * (0...65535, inclusive) then the flow will be visible to OpenFlow * controllers; otherwise, it will be hidden. * - * The caller retains ownership of 'cls_rule' and 'actions'. + * The caller retains ownership of 'cls_rule' and 'ofpacts'. * * This is a helper function for in-band control and fail-open. */ void ofproto_add_flow(struct ofproto *ofproto, const struct cls_rule *cls_rule, - const union ofp_action *actions, size_t n_actions) + const struct ofpact *ofpacts, size_t ofpacts_len) { const struct rule *rule; rule = rule_from_cls_rule(classifier_find_rule_exactly( &ofproto->tables[0].cls, cls_rule)); - if (!rule || !ofputil_actions_equal(rule->actions, rule->n_actions, - actions, n_actions)) { + if (!rule || !ofpacts_equal(rule->ofpacts, rule->ofpacts_len, + ofpacts, ofpacts_len)) { struct ofputil_flow_mod fm; memset(&fm, 0, sizeof fm); fm.cr = *cls_rule; fm.buffer_id = UINT32_MAX; - fm.actions = (union ofp_action *) actions; - fm.n_actions = n_actions; + fm.ofpacts = xmemdup(ofpacts, ofpacts_len); + fm.ofpacts_len = ofpacts_len; add_flow(ofproto, NULL, &fm, NULL); + free(fm.ofpacts); } } @@ -1791,7 +1859,7 @@ static void ofproto_rule_destroy__(struct rule *rule) { if (rule) { - free(rule->actions); + free(rule->ofpacts); rule->ofproto->ofproto_class->rule_dealloc(rule); } } @@ -1813,23 +1881,12 @@ ofproto_rule_destroy(struct rule *rule) } /* Returns true if 'rule' has an OpenFlow OFPAT_OUTPUT or OFPAT_ENQUEUE action - * that outputs to 'out_port' (output to OFPP_FLOOD and OFPP_ALL doesn't - * count). */ + * that outputs to 'port' (output to OFPP_FLOOD and OFPP_ALL doesn't count). */ static bool -rule_has_out_port(const struct rule *rule, uint16_t out_port) +rule_has_out_port(const struct rule *rule, uint16_t port) { - const union ofp_action *oa; - size_t left; - - if (out_port == OFPP_NONE) { - return true; - } - OFPUTIL_ACTION_FOR_EACH_UNSAFE (oa, left, rule->actions, rule->n_actions) { - if (action_outputs_to_port(oa, htons(out_port))) { - return true; - } - } - return false; + return (port == OFPP_NONE + || ofpacts_output_to_port(rule->ofpacts, rule->ofpacts_len, port)); } /* Executes the actions indicated by 'rule' on 'packet' and credits 'rule''s @@ -1986,6 +2043,8 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo) struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofputil_packet_out po; struct ofpbuf *payload; + uint64_t ofpacts_stub[1024 / 8]; + struct ofpbuf ofpacts; struct flow flow; enum ofperr error; @@ -1993,20 +2052,21 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo) error = reject_slave_controller(ofconn); if (error) { - return error; + goto exit; } /* Decode message. */ - error = ofputil_decode_packet_out(&po, opo); + ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); + error = ofputil_decode_packet_out(&po, opo, &ofpacts); if (error) { - return error; + goto exit_free_ofpacts; } /* Get payload. */ if (po.buffer_id != UINT32_MAX) { error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL); if (error || !payload) { - return error; + goto exit_free_ofpacts; } } else { payload = xmalloc(sizeof *payload); @@ -2016,9 +2076,12 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo) /* Send out packet. */ flow_extract(payload, 0, 0, po.in_port, &flow); error = p->ofproto_class->packet_out(p, payload, &flow, - po.actions, po.n_actions); + po.ofpacts, po.ofpacts_len); ofpbuf_delete(payload); +exit_free_ofpacts: + ofpbuf_uninit(&ofpacts); +exit: return error; } @@ -2112,7 +2175,7 @@ handle_table_stats_request(struct ofconn *ofconn, for (i = 0; i < p->n_tables; i++) { ots[i].table_id = i; sprintf(ots[i].name, "table%zu", i); - ots[i].wildcards = htonl(OFPFW_ALL); + ots[i].wildcards = htonl(OFPFW10_ALL); ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */ ots[i].active_count = htonl(classifier_count(&p->tables[i].cls)); } @@ -2420,8 +2483,8 @@ handle_flow_stats_request(struct ofconn *ofconn, fs.hard_age = age_secs(now - rule->modified); ofproto->ofproto_class->rule_get_stats(rule, &fs.packet_count, &fs.byte_count); - fs.actions = rule->actions; - fs.n_actions = rule->n_actions; + fs.ofpacts = rule->ofpacts; + fs.ofpacts_len = rule->ofpacts_len; ofputil_append_flow_stats_reply(&fs, &replies); } ofconn_send_replies(ofconn, &replies); @@ -2447,8 +2510,8 @@ flow_stats_ds(struct rule *rule, struct ds *results) ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count); cls_rule_format(&rule->cr, results); ds_put_char(results, ','); - if (rule->n_actions > 0) { - ofp_print_actions(results, rule->actions, rule->n_actions); + if (rule->ofpacts_len > 0) { + ofpacts_format(rule->ofpacts, rule->ofpacts_len, results); } else { ds_put_cstr(results, "drop"); } @@ -2618,7 +2681,7 @@ handle_queue_stats_dump_cb(uint32_t queue_id, put_queue_stats(cbdata, queue_id, stats); } -static void +static enum ofperr handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id, struct queue_stats_cbdata *cbdata) { @@ -2631,8 +2694,11 @@ handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id, if (!netdev_get_queue_stats(port->netdev, queue_id, &stats)) { put_queue_stats(cbdata, queue_id, &stats); + } else { + return OFPERR_OFPQOFC_BAD_QUEUE; } } + return 0; } static enum ofperr @@ -2641,9 +2707,10 @@ handle_queue_stats_request(struct ofconn *ofconn, { struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct queue_stats_cbdata cbdata; - struct ofport *port; unsigned int port_no; + struct ofport *port; uint32_t queue_id; + enum ofperr error; COVERAGE_INC(ofproto_queue_req); @@ -2652,21 +2719,25 @@ handle_queue_stats_request(struct ofconn *ofconn, port_no = ntohs(qsr->port_no); queue_id = ntohl(qsr->queue_id); if (port_no == OFPP_ALL) { + error = OFPERR_OFPQOFC_BAD_QUEUE; HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) { - handle_queue_stats_for_port(port, queue_id, &cbdata); + if (!handle_queue_stats_for_port(port, queue_id, &cbdata)) { + error = 0; + } } - } else if (port_no < OFPP_MAX) { + } else { port = ofproto_get_port(ofproto, port_no); - if (port) { - handle_queue_stats_for_port(port, queue_id, &cbdata); - } + error = (port + ? handle_queue_stats_for_port(port, queue_id, &cbdata) + : OFPERR_OFPQOFC_BAD_PORT); + } + if (!error) { + ofconn_send_replies(ofconn, &cbdata.replies); } else { ofpbuf_list_delete(&cbdata.replies); - return OFPERR_OFPQOFC_BAD_PORT; } - ofconn_send_replies(ofconn, &cbdata.replies); - return 0; + return error; } static bool @@ -2697,6 +2768,9 @@ is_flow_deletion_pending(const struct ofproto *ofproto, * error code on failure, or OFPROTO_POSTPONE if the operation cannot be * initiated now but may be retried later. * + * Upon successful return, takes ownership of 'fm->ofpacts'. On failure, + * ownership remains with the caller. + * * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id, * if any. */ static enum ofperr @@ -2759,14 +2833,14 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, rule->ofproto = ofproto; rule->cr = fm->cr; rule->pending = NULL; - rule->flow_cookie = fm->cookie; + rule->flow_cookie = fm->new_cookie; rule->created = rule->modified = rule->used = time_msec(); rule->idle_timeout = fm->idle_timeout; rule->hard_timeout = fm->hard_timeout; rule->table_id = table - ofproto->tables; rule->send_flow_removed = (fm->flags & OFPFF_SEND_FLOW_REM) != 0; - rule->actions = ofputil_actions_clone(fm->actions, fm->n_actions); - rule->n_actions = fm->n_actions; + rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len); + rule->ofpacts_len = fm->ofpacts_len; rule->evictable = true; rule->eviction_group = NULL; @@ -2848,18 +2922,20 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn, continue; } - if (!ofputil_actions_equal(fm->actions, fm->n_actions, - rule->actions, rule->n_actions)) { + if (!ofpacts_equal(fm->ofpacts, fm->ofpacts_len, + rule->ofpacts, rule->ofpacts_len)) { ofoperation_create(group, rule, OFOPERATION_MODIFY); - rule->pending->actions = rule->actions; - rule->pending->n_actions = rule->n_actions; - rule->actions = ofputil_actions_clone(fm->actions, fm->n_actions); - rule->n_actions = fm->n_actions; - ofproto->ofproto_class->rule_modify_actions(rule); + rule->pending->ofpacts = rule->ofpacts; + rule->pending->ofpacts_len = rule->ofpacts_len; + rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len); + rule->ofpacts_len = fm->ofpacts_len; + rule->ofproto->ofproto_class->rule_modify_actions(rule); } else { rule->modified = time_msec(); } - rule->flow_cookie = fm->cookie; + if (fm->new_cookie != htonll(UINT64_MAX)) { + rule->flow_cookie = fm->new_cookie; + } } ofopgroup_submit(group); @@ -2882,9 +2958,13 @@ modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn, error = collect_rules_loose(ofproto, fm->table_id, &fm->cr, fm->cookie, fm->cookie_mask, OFPP_NONE, &rules); - return (error ? error - : list_is_empty(&rules) ? add_flow(ofproto, ofconn, fm, request) - : modify_flows__(ofproto, ofconn, fm, request, &rules)); + if (error) { + return error; + } else if (list_is_empty(&rules)) { + return fm->cookie_mask ? 0 : add_flow(ofproto, ofconn, fm, request); + } else { + return modify_flows__(ofproto, ofconn, fm, request, &rules); + } } /* Implements OFPFC_MODIFY_STRICT. Returns 0 on success or an OpenFlow error @@ -2903,11 +2983,16 @@ modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn, error = collect_rules_strict(ofproto, fm->table_id, &fm->cr, fm->cookie, fm->cookie_mask, OFPP_NONE, &rules); - return (error ? error - : list_is_empty(&rules) ? add_flow(ofproto, ofconn, fm, request) - : list_is_singleton(&rules) ? modify_flows__(ofproto, ofconn, - fm, request, &rules) - : 0); + + if (error) { + return error; + } else if (list_is_empty(&rules)) { + return fm->cookie_mask ? 0 : add_flow(ofproto, ofconn, fm, request); + } else { + return list_is_singleton(&rules) ? modify_flows__(ofproto, ofconn, + fm, request, &rules) + : 0; + } } /* OFPFC_DELETE implementation. */ @@ -3040,28 +3125,69 @@ ofproto_rule_expire(struct rule *rule, uint8_t reason) static enum ofperr handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) { + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofputil_flow_mod fm; + uint64_t ofpacts_stub[1024 / 8]; + struct ofpbuf ofpacts; enum ofperr error; + long long int now; error = reject_slave_controller(ofconn); if (error) { - return error; + goto exit; } - error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn)); + ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); + error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn), + &ofpacts); if (error) { - return error; + goto exit_free_ofpacts; } - /* We do not support the emergency flow cache. It will hopefully get - * dropped from OpenFlow in the near future. */ + /* We do not support the OpenFlow 1.0 emergency flow cache, which is not + * required in OpenFlow 1.0.1 and removed from OpenFlow 1.1. */ if (fm.flags & OFPFF_EMERG) { - /* There isn't a good fit for an error code, so just state that the - * flow table is full. */ - return OFPERR_OFPFMFC_ALL_TABLES_FULL; + /* We do not support the emergency flow cache. It will hopefully get + * dropped from OpenFlow in the near future. There is no good error + * code, so just state that the flow table is full. */ + error = OFPERR_OFPFMFC_ALL_TABLES_FULL; + } else { + error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh); + } + if (error) { + goto exit_free_ofpacts; + } + + /* Record the operation for logging a summary report. */ + switch (fm.command) { + case OFPFC_ADD: + ofproto->n_add++; + break; + + case OFPFC_MODIFY: + case OFPFC_MODIFY_STRICT: + ofproto->n_modify++; + break; + + case OFPFC_DELETE: + case OFPFC_DELETE_STRICT: + ofproto->n_delete++; + break; } - return handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh); + now = time_msec(); + if (ofproto->next_op_report == LLONG_MAX) { + ofproto->first_op = now; + ofproto->next_op_report = MAX(now + 10 * 1000, + ofproto->op_backoff); + ofproto->op_backoff = ofproto->next_op_report + 60 * 1000; + } + ofproto->last_op = now; + +exit_free_ofpacts: + ofpbuf_uninit(&ofpacts); +exit: + return error; } static enum ofperr @@ -3205,6 +3331,10 @@ handle_nxt_set_async_config(struct ofconn *ofconn, const struct ofp_header *oh) slave[OAM_FLOW_REMOVED] = ntohl(msg->flow_removed_mask[1]); ofconn_set_async_config(ofconn, master, slave); + if (ofconn_get_type(ofconn) == OFCONN_SERVICE && + !ofconn_get_miss_send_len(ofconn)) { + ofconn_set_miss_send_len(ofconn, OFP_DEFAULT_MISS_SEND_LEN); + } return 0; } @@ -3227,14 +3357,13 @@ handle_nxt_set_controller_id(struct ofconn *ofconn, static enum ofperr handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh) { - struct ofp_header *ob; struct ofpbuf *buf; if (ofconn_has_pending_opgroups(ofconn)) { return OFPROTO_POSTPONE; } - ob = make_openflow_xid(sizeof *ob, OFPT10_BARRIER_REPLY, oh->xid, &buf); + make_openflow_xid(sizeof *oh, OFPT10_BARRIER_REPLY, oh->xid, &buf); ofconn_send_reply(ofconn, buf); return 0; } @@ -3464,6 +3593,7 @@ static void ofoperation_create(struct ofopgroup *group, struct rule *rule, enum ofoperation_type type) { + struct ofproto *ofproto = group->ofproto; struct ofoperation *op; assert(!rule->pending); @@ -3473,11 +3603,10 @@ ofoperation_create(struct ofopgroup *group, struct rule *rule, list_push_back(&group->ops, &op->group_node); op->rule = rule; op->type = type; - op->status = -1; op->flow_cookie = rule->flow_cookie; if (type == OFOPERATION_DELETE) { - hmap_insert(&op->group->ofproto->deletions, &op->hmap_node, + hmap_insert(&ofproto->deletions, &op->hmap_node, cls_rule_hash(&rule->cr, rule->table_id)); } } @@ -3494,7 +3623,7 @@ ofoperation_destroy(struct ofoperation *op) hmap_remove(&group->ofproto->deletions, &op->hmap_node); } list_remove(&op->group_node); - free(op->actions); + free(op->ofpacts); free(op); if (list_is_empty(&group->ops) && !list_is_empty(&group->ofproto_node)) { @@ -3539,7 +3668,6 @@ ofoperation_complete(struct ofoperation *op, enum ofperr error) struct ofproto *ofproto = rule->ofproto; assert(rule->pending == op); - assert(op->status < 0); if (!error && !group->error @@ -3581,6 +3709,7 @@ ofoperation_complete(struct ofoperation *op, enum ofperr error) } else { oftable_substitute_rule(rule, op->victim); ofproto_rule_destroy__(rule); + op->rule = NULL; } break; @@ -3594,10 +3723,10 @@ ofoperation_complete(struct ofoperation *op, enum ofperr error) if (!error) { rule->modified = time_msec(); } else { - free(rule->actions); - rule->actions = op->actions; - rule->n_actions = op->n_actions; - op->actions = NULL; + free(rule->ofpacts); + rule->ofpacts = op->ofpacts; + rule->ofpacts_len = op->ofpacts_len; + op->ofpacts = NULL; } break; @@ -3897,6 +4026,7 @@ oftable_init(struct oftable *table) { memset(table, 0, sizeof *table); classifier_init(&table->cls); + table->max_flows = UINT_MAX; } /* Destroys 'table', including its classifier and eviction groups.