X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=a517264f5a19077d9baaae299042549d1c1f4169;hb=045c0d1a77ae0592658f69ce071018ef32938253;hp=884e63ef8377b987fb4760736385a3b94fc328a4;hpb=8917f72cbb04fb32dc29f93475bcd2de3011d442;p=sliver-openvswitch.git diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 884e63ef8..a517264f5 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -43,6 +43,7 @@ #include "ofproto-provider.h" #include "openflow/nicira-ext.h" #include "openflow/openflow.h" +#include "ovs-rcu.h" #include "packets.h" #include "pinsched.h" #include "pktbuf.h" @@ -260,7 +261,8 @@ struct ofport_usage { /* rule. */ static void ofproto_rule_destroy__(struct rule *); static void ofproto_rule_send_removed(struct rule *, uint8_t reason); -static bool rule_is_modifiable(const struct rule *); +static bool rule_is_modifiable(const struct rule *rule, + enum ofputil_flow_mod_flags flag); /* OpenFlow. */ static enum ofperr add_flow(struct ofproto *, struct ofconn *, @@ -1142,6 +1144,24 @@ ofproto_get_n_tables(const struct ofproto *ofproto) return ofproto->n_tables; } +/* Returns the number of Controller visible OpenFlow tables + * in 'ofproto'. This number will exclude Hidden tables. + * This funtion's return value should be less or equal to that of + * ofproto_get_n_tables() . */ +uint8_t +ofproto_get_n_visible_tables(const struct ofproto *ofproto) +{ + uint8_t n = ofproto->n_tables; + + /* Count only non-hidden tables in the number of tables. (Hidden tables, + * if present, are always at the end.) */ + while(n && (ofproto->tables[n - 1].flags & OFTABLE_HIDDEN)) { + n--; + } + + return n; +} + /* Configures the OpenFlow table in 'ofproto' with id 'table_id' with the * settings from 's'. 'table_id' must be in the range 0 through the number of * OpenFlow tables in 'ofproto' minus 1, inclusive. @@ -1910,11 +1930,9 @@ ofproto_add_flow(struct ofproto *ofproto, const struct match *match, rule = rule_from_cls_rule(classifier_find_match_exactly( &ofproto->tables[0].cls, match, priority)); if (rule) { - ovs_mutex_lock(&rule->mutex); - must_add = !ofpacts_equal(rule->actions->ofpacts, - rule->actions->ofpacts_len, + struct rule_actions *actions = rule_get_actions(rule); + must_add = !ofpacts_equal(actions->ofpacts, actions->ofpacts_len, ofpacts, ofpacts_len); - ovs_mutex_unlock(&rule->mutex); } else { must_add = true; } @@ -1958,14 +1976,16 @@ ofproto_flow_mod(struct ofproto *ofproto, struct ofputil_flow_mod *fm) /* Reading many of the rule fields and writing on 'modified' * requires the rule->mutex. Also, rule->actions may change * if rule->mutex is not held. */ + const struct rule_actions *actions; + ovs_mutex_lock(&rule->mutex); + actions = rule_get_actions(rule); if (rule->idle_timeout == fm->idle_timeout && rule->hard_timeout == fm->hard_timeout && rule->flags == (fm->flags & OFPUTIL_FF_STATE) && (!fm->modify_cookie || (fm->new_cookie == rule->flow_cookie)) && ofpacts_equal(fm->ofpacts, fm->ofpacts_len, - rule->actions->ofpacts, - rule->actions->ofpacts_len)) { + actions->ofpacts, actions->ofpacts_len)) { /* Rule already exists and need not change, only update the modified timestamp. */ rule->modified = time_msec(); @@ -2587,33 +2607,12 @@ ofproto_rule_unref(struct rule *rule) } } -struct rule_actions * -rule_get_actions(const struct rule *rule) - OVS_EXCLUDED(rule->mutex) -{ - struct rule_actions *actions; - - ovs_mutex_lock(&rule->mutex); - actions = rule_get_actions__(rule); - ovs_mutex_unlock(&rule->mutex); - - return actions; -} - -struct rule_actions * -rule_get_actions__(const struct rule *rule) - OVS_REQUIRES(rule->mutex) -{ - rule_actions_ref(rule->actions); - return rule->actions; -} - static void ofproto_rule_destroy__(struct rule *rule) OVS_NO_THREAD_SAFETY_ANALYSIS { cls_rule_destroy(CONST_CAST(struct cls_rule *, &rule->cr)); - rule_actions_unref(rule->actions); + rule_actions_destroy(rule_get_actions(rule)); ovs_mutex_destroy(&rule->mutex); rule->ofproto->ofproto_class->rule_dealloc(rule); } @@ -2630,7 +2629,6 @@ rule_actions_create(const struct ofproto *ofproto, struct rule_actions *actions; actions = xmalloc(sizeof *actions); - ovs_refcount_init(&actions->ref_count); actions->ofpacts = xmemdup(ofpacts, ofpacts_len); actions->ofpacts_len = ofpacts_len; actions->provider_meter_id @@ -2640,23 +2638,20 @@ rule_actions_create(const struct ofproto *ofproto, return actions; } -/* Increments 'actions''s ref_count. */ -void -rule_actions_ref(struct rule_actions *actions) +static void +rule_actions_destroy_cb(struct rule_actions *actions) { - if (actions) { - ovs_refcount_ref(&actions->ref_count); - } + free(actions->ofpacts); + free(actions); } /* Decrements 'actions''s ref_count and frees 'actions' if the ref_count * reaches 0. */ void -rule_actions_unref(struct rule_actions *actions) +rule_actions_destroy(struct rule_actions *actions) { - if (actions && ovs_refcount_unref(&actions->ref_count) == 1) { - free(actions->ofpacts); - free(actions); + if (actions) { + ovsrcu_postpone(rule_actions_destroy_cb, actions); } } @@ -2666,9 +2661,13 @@ static bool ofproto_rule_has_out_port(const struct rule *rule, ofp_port_t port) OVS_REQUIRES(ofproto_mutex) { - return (port == OFPP_ANY - || ofpacts_output_to_port(rule->actions->ofpacts, - rule->actions->ofpacts_len, port)); + if (port == OFPP_ANY) { + return true; + } else { + const struct rule_actions *actions = rule_get_actions(rule); + return ofpacts_output_to_port(actions->ofpacts, + actions->ofpacts_len, port); + } } /* Returns true if 'rule' has group and equals group_id. */ @@ -2676,9 +2675,13 @@ static bool ofproto_rule_has_out_group(const struct rule *rule, uint32_t group_id) OVS_REQUIRES(ofproto_mutex) { - return (group_id == OFPG11_ANY - || ofpacts_output_to_group(rule->actions->ofpacts, - rule->actions->ofpacts_len, group_id)); + if (group_id == OFPG_ANY) { + return true; + } else { + const struct rule_actions *actions = rule_get_actions(rule); + return ofpacts_output_to_group(actions->ofpacts, + actions->ofpacts_len, group_id); + } } /* Returns true if a rule related to 'op' has an OpenFlow OFPAT_OUTPUT or @@ -2757,19 +2760,27 @@ destroy_rule_executes(struct ofproto *ofproto) static bool ofproto_rule_is_hidden(const struct rule *rule) { - return rule->cr.priority > UINT16_MAX; + return (rule->cr.priority > UINT16_MAX); } -static enum oftable_flags -rule_get_flags(const struct rule *rule) +static bool +oftable_is_modifiable(const struct oftable *table, + enum ofputil_flow_mod_flags flags) { - return rule->ofproto->tables[rule->table_id].flags; + if (flags & OFPUTIL_FF_NO_READONLY) { + return true; + } + + return !(table->flags & OFTABLE_READONLY); } static bool -rule_is_modifiable(const struct rule *rule) +rule_is_modifiable(const struct rule *rule, enum ofputil_flow_mod_flags flags) { - return !(rule_get_flags(rule) & OFTABLE_READONLY); + const struct oftable *rule_table; + + rule_table = &rule->ofproto->tables[rule->table_id]; + return oftable_is_modifiable(rule_table, flags); } static enum ofperr @@ -2787,26 +2798,14 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) struct ofport *port; bool arp_match_ip; struct ofpbuf *b; - int n_tables; - int i; ofproto->ofproto_class->get_features(ofproto, &arp_match_ip, &features.actions); ovs_assert(features.actions & OFPUTIL_A_OUTPUT); /* sanity check */ - /* Count only non-hidden tables in the number of tables. (Hidden tables, - * if present, are always at the end.) */ - n_tables = ofproto->n_tables; - for (i = 0; i < ofproto->n_tables; i++) { - if (ofproto->tables[i].flags & OFTABLE_HIDDEN) { - n_tables = i; - break; - } - } - features.datapath_id = ofproto->datapath_id; features.n_buffers = pktbuf_capacity(); - features.n_tables = n_tables; + features.n_tables = ofproto_get_n_visible_tables(ofproto); features.capabilities = (OFPUTIL_C_FLOW_STATS | OFPUTIL_C_TABLE_STATS | OFPUTIL_C_PORT_STATS | OFPUTIL_C_QUEUE_STATS); if (arp_match_ip) { @@ -3208,8 +3207,7 @@ handle_port_desc_stats_request(struct ofconn *ofconn, static uint32_t hash_cookie(ovs_be64 cookie) { - return hash_2words((OVS_FORCE uint64_t)cookie >> 32, - (OVS_FORCE uint64_t)cookie); + return hash_uint64((OVS_FORCE uint64_t)cookie); } static void @@ -3606,7 +3604,7 @@ handle_flow_stats_request(struct ofconn *ofconn, fs.hard_timeout = rule->hard_timeout; created = rule->created; modified = rule->modified; - actions = rule_get_actions__(rule); + actions = rule_get_actions(rule); flags = rule->flags; ovs_mutex_unlock(&rule->mutex); @@ -3624,8 +3622,6 @@ handle_flow_stats_request(struct ofconn *ofconn, fs.flags = flags; ofputil_append_flow_stats_reply(&fs, &replies); - - rule_actions_unref(actions); } rule_collection_unref(&rules); @@ -3647,7 +3643,7 @@ flow_stats_ds(struct rule *rule, struct ds *results) &byte_count, &used); ovs_mutex_lock(&rule->mutex); - actions = rule_get_actions__(rule); + actions = rule_get_actions(rule); created = rule->created; ovs_mutex_unlock(&rule->mutex); @@ -3664,8 +3660,6 @@ flow_stats_ds(struct rule *rule, struct ds *results) ofpacts_format(actions->ofpacts, actions->ofpacts_len, results); ds_put_cstr(results, "\n"); - - rule_actions_unref(actions); } /* Adds a pretty-printed description of all flows to 'results', including @@ -3989,10 +3983,18 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, table = &ofproto->tables[table_id]; - if (table->flags & OFTABLE_READONLY) { + if (!oftable_is_modifiable(table, fm->flags)) { return OFPERR_OFPBRC_EPERM; } + if (!(fm->flags & OFPUTIL_FF_HIDDEN_FIELDS)) { + if (!match_has_default_hidden_fields(&fm->match)) { + VLOG_WARN_RL(&rl, "%s: (add_flow) only internal flows can set " + "non-default values to hidden fields", ofproto->name); + return OFPERR_OFPBRC_EPERM; + } + } + cls_rule_init(&cr, &fm->match, fm->priority); /* Transform "add" into "modify" if there's an existing identical flow. */ @@ -4001,7 +4003,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, fat_rwlock_unlock(&table->cls.rwlock); if (rule) { cls_rule_destroy(&cr); - if (!rule_is_modifiable(rule)) { + if (!rule_is_modifiable(rule, fm->flags)) { return OFPERR_OFPBRC_EPERM; } else if (rule->pending) { return OFPROTO_POSTPONE; @@ -4070,7 +4072,8 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, *CONST_CAST(uint8_t *, &rule->table_id) = table - ofproto->tables; rule->flags = fm->flags & OFPUTIL_FF_STATE; - rule->actions = rule_actions_create(ofproto, fm->ofpacts, fm->ofpacts_len); + ovsrcu_set(&rule->actions, + rule_actions_create(ofproto, fm->ofpacts, fm->ofpacts_len)); list_init(&rule->meter_list_node); rule->eviction_group = NULL; list_init(&rule->expirable); @@ -4121,22 +4124,24 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn, error = OFPERR_OFPBRC_EPERM; for (i = 0; i < rules->n; i++) { struct rule *rule = rules->rules[i]; + const struct rule_actions *actions; struct ofoperation *op; bool actions_changed; bool reset_counters; /* FIXME: Implement OFPFUTIL_FF_RESET_COUNTS */ - if (rule_is_modifiable(rule)) { + if (rule_is_modifiable(rule, fm->flags)) { /* At least one rule is modifiable, don't report EPERM error. */ error = 0; } else { continue; } + actions = rule_get_actions(rule); actions_changed = !ofpacts_equal(fm->ofpacts, fm->ofpacts_len, - rule->actions->ofpacts, - rule->actions->ofpacts_len); + actions->ofpacts, + actions->ofpacts_len); op = ofoperation_create(group, rule, type, 0); @@ -4163,13 +4168,11 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn, if (actions_changed || reset_counters) { struct rule_actions *new_actions; - op->actions = rule->actions; + op->actions = rule_get_actions(rule); new_actions = rule_actions_create(ofproto, fm->ofpacts, fm->ofpacts_len); - ovs_mutex_lock(&rule->mutex); - rule->actions = new_actions; - ovs_mutex_unlock(&rule->mutex); + ovsrcu_set(&rule->actions, new_actions); rule->ofproto->ofproto_class->rule_modify_actions(rule, reset_counters); @@ -4750,7 +4753,7 @@ ofproto_compose_flow_refresh_update(const struct rule *rule, if (!(flags & NXFMF_ACTIONS)) { actions = NULL; } else if (!op) { - actions = rule->actions; + actions = rule_get_actions(rule); } else { /* An operation is in progress. Use the previous version of the flow's * actions, so that when the operation commits we report the change. */ @@ -4760,11 +4763,11 @@ ofproto_compose_flow_refresh_update(const struct rule *rule, case OFOPERATION_MODIFY: case OFOPERATION_REPLACE: - actions = op->actions ? op->actions : rule->actions; + actions = op->actions ? op->actions : rule_get_actions(rule); break; case OFOPERATION_DELETE: - actions = rule->actions; + actions = rule_get_actions(rule); break; default: @@ -5806,11 +5809,21 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh) } } +enum ofproto_table_config +ofproto_table_get_config(const struct ofproto *ofproto, uint8_t table_id) +{ + unsigned int value; + atomic_read(&ofproto->tables[table_id].config, &value); + return (enum ofproto_table_config)value; +} + static enum ofperr table_mod(struct ofproto *ofproto, const struct ofputil_table_mod *tm) { - /* XXX Reject all configurations because none are currently supported */ - return OFPERR_OFPTMFC_BAD_CONFIG; + /* Only accept currently supported configurations */ + if (tm->config & ~OFPTC11_TABLE_MISS_MASK) { + return OFPERR_OFPTMFC_BAD_CONFIG; + } if (tm->table_id == OFPTT_ALL) { int i; @@ -5852,7 +5865,7 @@ static enum ofperr handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) OVS_EXCLUDED(ofproto_mutex) { - const struct ofp_header *oh = msg->data; + const struct ofp_header *oh = ofpbuf_data(msg); enum ofptype type; enum ofperr error; @@ -6025,7 +6038,7 @@ handle_openflow(struct ofconn *ofconn, const struct ofpbuf *ofp_msg) { int error = handle_openflow__(ofconn, ofp_msg); if (error && error != OFPROTO_POSTPONE) { - ofconn_send_error(ofconn, ofp_msg->data, error); + ofconn_send_error(ofconn, ofpbuf_data(ofp_msg), error); } COVERAGE_INC(ofproto_recv_openflow); return error != OFPROTO_POSTPONE; @@ -6254,12 +6267,12 @@ ofopgroup_complete(struct ofopgroup *group) struct rule_actions *old_actions; ovs_mutex_lock(&rule->mutex); - old_actions = rule->actions; - rule->actions = op->actions; + old_actions = rule_get_actions(rule); + ovsrcu_set(&rule->actions, op->actions); ovs_mutex_unlock(&rule->mutex); op->actions = NULL; - rule_actions_unref(old_actions); + rule_actions_destroy(old_actions); } rule->flags = op->flags; } @@ -6345,7 +6358,7 @@ ofoperation_destroy(struct ofoperation *op) hmap_remove(&group->ofproto->deletions, &op->hmap_node); } list_remove(&op->group_node); - rule_actions_unref(op->actions); + rule_actions_destroy(op->actions); free(op); } @@ -6688,7 +6701,7 @@ oftable_init(struct oftable *table) memset(table, 0, sizeof *table); classifier_init(&table->cls, flow_segment_u32s); table->max_flows = UINT_MAX; - atomic_init(&table->config, (unsigned int)OFPTC11_TABLE_MISS_CONTROLLER); + atomic_init(&table->config, (unsigned int)OFPROTO_TABLE_MISS_DEFAULT); } /* Destroys 'table', including its classifier and eviction groups. @@ -6827,6 +6840,7 @@ oftable_insert_rule(struct rule *rule) { struct ofproto *ofproto = rule->ofproto; struct oftable *table = &ofproto->tables[rule->table_id]; + struct rule_actions *actions; bool may_expire; ovs_mutex_lock(&rule->mutex); @@ -6839,9 +6853,10 @@ oftable_insert_rule(struct rule *rule) cookies_insert(ofproto, rule); - if (rule->actions->provider_meter_id != UINT32_MAX) { - uint32_t meter_id = ofpacts_get_meter(rule->actions->ofpacts, - rule->actions->ofpacts_len); + actions = rule_get_actions(rule); + if (actions->provider_meter_id != UINT32_MAX) { + uint32_t meter_id = ofpacts_get_meter(actions->ofpacts, + actions->ofpacts_len); struct meter *meter = ofproto->meters[meter_id]; list_insert(&meter->rules, &rule->meter_list_node); }