X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=abf14f2952954f3b9c1095df54c746c7bb78b145;hb=cc86b1f84b1e2fe1b322a23a2b3b88c0375f2fa1;hp=21155dcda000829df7f279ffbf30c183f661cd9c;hpb=7395c05254df87ce52b37b04478e802befd799d9;p=sliver-openvswitch.git diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 21155dcda..abf14f295 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -155,10 +155,10 @@ static void oftable_enable_eviction(struct oftable *, const struct mf_subfield *fields, size_t n_fields); -static void oftable_remove_rule(struct rule *rule) OVS_RELEASES(rule->evict); +static void oftable_remove_rule(struct rule *rule) OVS_RELEASES(rule->rwlock); static void oftable_remove_rule__(struct ofproto *ofproto, struct classifier *cls, struct rule *rule) - OVS_REQ_WRLOCK(cls->rwlock) OVS_RELEASES(rule->evict); + OVS_REQ_WRLOCK(cls->rwlock) OVS_RELEASES(rule->rwlock); static void oftable_insert_rule(struct rule *); /* A set of rules within a single OpenFlow table (oftable) that have the same @@ -184,7 +184,7 @@ struct eviction_group { }; static bool choose_rule_to_evict(struct oftable *table, struct rule **rulep) - OVS_TRY_WRLOCK(true, (*rulep)->evict); + OVS_TRY_WRLOCK(true, (*rulep)->rwlock); static void ofproto_evict(struct ofproto *); static uint32_t rule_eviction_priority(struct rule *); static void eviction_group_add_rule(struct rule *); @@ -199,6 +199,7 @@ static int init_ports(struct ofproto *); static void reinit_ports(struct ofproto *); /* rule. */ +static void ofproto_rule_destroy(struct 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 *); @@ -212,7 +213,7 @@ static enum ofperr modify_flows__(struct ofproto *, struct ofconn *, const struct ofp_header *, struct list *); static void delete_flow__(struct rule *rule, struct ofopgroup *, enum ofp_flow_removed_reason) - OVS_RELEASES(rule->evict); + OVS_RELEASES(rule->rwlock); static enum ofperr add_group(struct ofproto *, struct ofputil_group_mod *); static bool handle_openflow(struct ofconn *, const struct ofpbuf *); static enum ofperr handle_flow_mod__(struct ofproto *, struct ofconn *, @@ -440,6 +441,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type, shash_init(&ofproto->port_by_name); simap_init(&ofproto->ofp_requests); ofproto->max_ports = ofp_to_u16(OFPP_MAX); + ofproto->eviction_group_timer = LLONG_MIN; ofproto->tables = NULL; ofproto->n_tables = 0; hindex_init(&ofproto->cookies); @@ -640,14 +642,15 @@ ofproto_set_mac_table_config(struct ofproto *ofproto, unsigned idle_time, } /* Sets number of upcall handler threads. The default is - * (number of online cores - 1). */ + * (number of online cores - 2). */ void ofproto_set_n_handler_threads(unsigned limit) { if (limit) { n_handler_threads = limit; } else { - n_handler_threads = MAX(1, sysconf(_SC_NPROCESSORS_ONLN) - 1); + int n_proc = sysconf(_SC_NPROCESSORS_ONLN); + n_handler_threads = n_proc > 2 ? n_proc - 2 : 1; } } @@ -1093,7 +1096,7 @@ ofproto_delete_rule(struct ofproto *ofproto, struct classifier *cls, group = ofopgroup_create_unattached(ofproto); ofoperation_create(group, rule, OFOPERATION_DELETE, OFPRR_DELETE); - ovs_rwlock_wrlock(&rule->evict); + ovs_rwlock_wrlock(&rule->rwlock); oftable_remove_rule__(ofproto, cls, rule); ofproto->ofproto_class->rule_delete(rule); ofopgroup_submit(group); @@ -1278,6 +1281,38 @@ ofproto_run(struct ofproto *p) VLOG_ERR_RL(&rl, "%s: run failed (%s)", p->name, ovs_strerror(error)); } + /* Restore the eviction group heap invariant occasionally. */ + if (p->eviction_group_timer < time_msec()) { + size_t i; + + p->eviction_group_timer = time_msec() + 1000; + + for (i = 0; i < p->n_tables; i++) { + struct oftable *table = &p->tables[i]; + struct eviction_group *evg; + struct cls_cursor cursor; + struct rule *rule; + + if (!table->eviction_fields) { + continue; + } + + HEAP_FOR_EACH (evg, size_node, &table->eviction_groups_by_size) { + heap_rebuild(&evg->rules); + } + + ovs_rwlock_rdlock(&table->cls.rwlock); + cls_cursor_init(&cursor, &table->cls, NULL); + CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { + if (!rule->eviction_group + && (rule->idle_timeout || rule->hard_timeout)) { + eviction_group_add_rule(rule); + } + } + ovs_rwlock_unlock(&table->cls.rwlock); + } + } + if (p->ofproto_class->port_poll) { char *devname; @@ -1847,8 +1882,8 @@ ofport_open(struct ofproto *ofproto, pp->state = netdev_get_carrier(netdev) ? 0 : OFPUTIL_PS_LINK_DOWN; netdev_get_features(netdev, &pp->curr, &pp->advertised, &pp->supported, &pp->peer); - pp->curr_speed = netdev_features_to_bps(pp->curr, 0); - pp->max_speed = netdev_features_to_bps(pp->supported, 0); + pp->curr_speed = netdev_features_to_bps(pp->curr, 0) / 1000; + pp->max_speed = netdev_features_to_bps(pp->supported, 0) / 1000; return netdev; } @@ -2222,18 +2257,24 @@ update_mtu(struct ofproto *p, struct ofport *port) } static void -ofproto_rule_destroy__(struct rule *rule) +ofproto_rule_destroy(struct rule *rule) { if (rule) { rule->ofproto->ofproto_class->rule_destruct(rule); - cls_rule_destroy(&rule->cr); - free(rule->ofpacts); - ovs_mutex_destroy(&rule->timeout_mutex); - ovs_rwlock_destroy(&rule->evict); - rule->ofproto->ofproto_class->rule_dealloc(rule); + ofproto_rule_destroy__(rule); } } +static void +ofproto_rule_destroy__(struct rule *rule) +{ + cls_rule_destroy(&rule->cr); + free(rule->ofpacts); + ovs_mutex_destroy(&rule->timeout_mutex); + ovs_rwlock_destroy(&rule->rwlock); + rule->ofproto->ofproto_class->rule_dealloc(rule); +} + /* This function allows an ofproto implementation to destroy any rules that * remain when its ->destruct() function is called.. This function implements * steps 4.4 and 4.5 in the section titled "Rule Life Cycle" in @@ -2809,7 +2850,9 @@ ofproto_rule_change_cookie(struct ofproto *ofproto, struct rule *rule, if (new_cookie != rule->flow_cookie) { cookies_remove(ofproto, rule); + ovs_rwlock_wrlock(&rule->rwlock); rule->flow_cookie = new_cookie; + ovs_rwlock_unlock(&rule->rwlock); cookies_insert(ofproto, rule); } @@ -2939,7 +2982,8 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id, goto exit; } if (rule->flow_cookie == cookie /* Hash collisions possible. */ - && ofproto_rule_has_out_port(rule, out_port)) { + && ofproto_rule_has_out_port(rule, out_port) + && ofproto_rule_has_out_group(rule, out_group)) { list_push_back(rules, &rule->ofproto_node); } } @@ -3021,7 +3065,8 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t table_id, goto exit; } if (rule->flow_cookie == cookie /* Hash collisions possible. */ - && ofproto_rule_has_out_port(rule, out_port)) { + && ofproto_rule_has_out_port(rule, out_port) + && ofproto_rule_has_out_group(rule, out_group)) { list_push_back(rules, &rule->ofproto_node); } } @@ -3384,7 +3429,7 @@ evict_rule_from_table(struct ofproto *ofproto, struct oftable *table) } else if (!choose_rule_to_evict(table, &rule)) { return OFPERR_OFPFMFC_TABLE_FULL; } else if (rule->pending) { - ovs_rwlock_unlock(&rule->evict); + ovs_rwlock_unlock(&rule->rwlock); return OFPROTO_POSTPONE; } else { struct ofopgroup *group; @@ -3477,6 +3522,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len, &fm->match.flow, table_id); if (error) { + cls_rule_destroy(&cr); return error; } @@ -3540,7 +3586,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn, rule->monitor_flags = 0; rule->add_seqno = 0; rule->modify_seqno = 0; - ovs_rwlock_init(&rule->evict); + ovs_rwlock_init(&rule->rwlock); /* Construct rule, initializing derived state. */ error = ofproto->ofproto_class->rule_construct(rule); @@ -3634,8 +3680,12 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn, op->ofpacts = rule->ofpacts; op->ofpacts_len = rule->ofpacts_len; op->meter_id = rule->meter_id; + + ovs_rwlock_wrlock(&rule->rwlock); rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len); rule->ofpacts_len = fm->ofpacts_len; + ovs_rwlock_unlock(&rule->rwlock); + rule->meter_id = find_meter(rule->ofpacts, rule->ofpacts_len); rule->ofproto->ofproto_class->rule_modify_actions(rule, reset_counters); @@ -3738,7 +3788,7 @@ delete_flows__(struct ofproto *ofproto, struct ofconn *ofconn, group = ofopgroup_create(ofproto, ofconn, request, UINT32_MAX); LIST_FOR_EACH_SAFE (rule, next, ofproto_node, rules) { - ovs_rwlock_wrlock(&rule->evict); + ovs_rwlock_wrlock(&rule->rwlock); delete_flow__(rule, group, reason); } ofopgroup_submit(group); @@ -3809,20 +3859,6 @@ ofproto_rule_send_removed(struct rule *rule, uint8_t reason) connmgr_send_flow_removed(rule->ofproto->connmgr, &fr); } -void -ofproto_rule_update_used(struct rule *rule, long long int used) -{ - if (used > rule->used) { - struct eviction_group *evg = rule->eviction_group; - - rule->used = used; - if (evg) { - heap_change(&evg->rules, &rule->evg_node, - rule_eviction_priority(rule)); - } - } -} - /* Sends an OpenFlow "flow removed" message with the given 'reason' (either * OFPRR_HARD_TIMEOUT or OFPRR_IDLE_TIMEOUT), and then removes 'rule' from its * ofproto. @@ -3881,10 +3917,6 @@ ofproto_rule_reduce_timeouts(struct rule *rule, reduce_timeout(idle_timeout, &rule->idle_timeout); reduce_timeout(hard_timeout, &rule->hard_timeout); ovs_mutex_unlock(&rule->timeout_mutex); - - if (!rule->eviction_group) { - eviction_group_add_rule(rule); - } } static enum ofperr @@ -4098,6 +4130,31 @@ handle_nxt_set_async_config(struct ofconn *ofconn, const struct ofp_header *oh) return 0; } +static enum ofperr +handle_nxt_get_async_request(struct ofconn *ofconn, const struct ofp_header *oh) +{ + struct ofpbuf *buf; + uint32_t master[OAM_N_TYPES]; + uint32_t slave[OAM_N_TYPES]; + struct nx_async_config *msg; + + ofconn_get_async_config(ofconn, master, slave); + buf = ofpraw_alloc_reply(OFPRAW_OFPT13_GET_ASYNC_REPLY, oh, 0); + msg = ofpbuf_put_zeros(buf, sizeof *msg); + + msg->packet_in_mask[0] = htonl(master[OAM_PACKET_IN]); + msg->port_status_mask[0] = htonl(master[OAM_PORT_STATUS]); + msg->flow_removed_mask[0] = htonl(master[OAM_FLOW_REMOVED]); + + msg->packet_in_mask[1] = htonl(slave[OAM_PACKET_IN]); + msg->port_status_mask[1] = htonl(slave[OAM_PORT_STATUS]); + msg->flow_removed_mask[1] = htonl(slave[OAM_FLOW_REMOVED]); + + ofconn_send_reply(ofconn, buf); + + return 0; +} + static enum ofperr handle_nxt_set_controller_id(struct ofconn *ofconn, const struct ofp_header *oh) @@ -4763,6 +4820,8 @@ append_group_stats(struct ofgroup *group, struct list *replies) long long int now = time_msec(); int error; + ogs.bucket_stats = xmalloc(group->n_buckets * sizeof *ogs.bucket_stats); + error = (ofproto->ofproto_class->group_get_stats ? ofproto->ofproto_class->group_get_stats(group, &ogs) : EOPNOTSUPP); @@ -4779,6 +4838,8 @@ append_group_stats(struct ofgroup *group, struct list *replies) calc_duration(group->created, now, &ogs.duration_sec, &ogs.duration_nsec); ofputil_append_group_stats(replies, &ogs); + + free(ogs.bucket_stats); } static enum ofperr @@ -5092,6 +5153,26 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh) } } +static enum ofperr +handle_table_mod(struct ofconn *ofconn, const struct ofp_header *oh) +{ + struct ofputil_table_mod tm; + enum ofperr error; + + error = reject_slave_controller(ofconn); + if (error) { + return error; + } + + error = ofputil_decode_table_mod(oh, &tm); + if (error) { + return error; + } + + /* XXX Actual table mod support is not implemented yet. */ + return 0; +} + static enum ofperr handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) { @@ -5130,6 +5211,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_GROUP_MOD: return handle_group_mod(ofconn, oh); + case OFPTYPE_TABLE_MOD: + return handle_table_mod(ofconn, oh); + case OFPTYPE_METER_MOD: return handle_meter_mod(ofconn, oh); @@ -5166,6 +5250,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_SET_ASYNC_CONFIG: return handle_nxt_set_async_config(ofconn, oh); + case OFPTYPE_GET_ASYNC_REQUEST: + return handle_nxt_get_async_request(ofconn, oh); + /* Statistics requests. */ case OFPTYPE_DESC_STATS_REQUEST: return handle_desc_stats_request(ofconn, oh); @@ -5209,7 +5296,6 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) /* FIXME: Change the following once they are implemented: */ case OFPTYPE_QUEUE_GET_CONFIG_REQUEST: - case OFPTYPE_GET_ASYNC_REQUEST: case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: return OFPERR_OFPBRC_BAD_TYPE; @@ -5429,15 +5515,15 @@ ofopgroup_complete(struct ofopgroup *group) } } } else { - ovs_rwlock_wrlock(&rule->evict); + ovs_rwlock_wrlock(&rule->rwlock); oftable_remove_rule(rule); - ofproto_rule_destroy__(rule); + ofproto_rule_destroy(rule); } break; case OFOPERATION_DELETE: ovs_assert(!op->error); - ofproto_rule_destroy__(rule); + ofproto_rule_destroy(rule); op->rule = NULL; break; @@ -5458,8 +5544,12 @@ ofopgroup_complete(struct ofopgroup *group) ovs_mutex_unlock(&rule->timeout_mutex); if (op->ofpacts) { free(rule->ofpacts); + + ovs_rwlock_wrlock(&rule->rwlock); rule->ofpacts = op->ofpacts; rule->ofpacts_len = op->ofpacts_len; + ovs_rwlock_unlock(&rule->rwlock); + op->ofpacts = NULL; op->ofpacts_len = 0; } @@ -5647,7 +5737,7 @@ choose_rule_to_evict(struct oftable *table, struct rule **rulep) struct rule *rule; HEAP_FOR_EACH (rule, evg_node, &evg->rules) { - if (!ovs_rwlock_trywrlock(&rule->evict)) { + if (!ovs_rwlock_trywrlock(&rule->rwlock)) { *rulep = rule; return true; } @@ -5688,7 +5778,7 @@ ofproto_evict(struct ofproto *ofproto) } if (rule->pending) { - ovs_rwlock_unlock(&rule->evict); + ovs_rwlock_unlock(&rule->rwlock); break; } @@ -5996,7 +6086,7 @@ oftable_enable_eviction(struct oftable *table, static void oftable_remove_rule__(struct ofproto *ofproto, struct classifier *cls, struct rule *rule) - OVS_REQ_WRLOCK(cls->rwlock) OVS_RELEASES(rule->evict) + OVS_REQ_WRLOCK(cls->rwlock) OVS_RELEASES(rule->rwlock) { classifier_remove(cls, &rule->cr); cookies_remove(ofproto, rule); @@ -6010,7 +6100,7 @@ oftable_remove_rule__(struct ofproto *ofproto, struct classifier *cls, list_remove(&rule->meter_list_node); list_init(&rule->meter_list_node); } - ovs_rwlock_unlock(&rule->evict); + ovs_rwlock_unlock(&rule->rwlock); } static void