X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=7ccff438c44f1a7afd2139687df3c3582fad7413;hb=HEAD;hp=f16005cecfc85884a8e48d2168519476779daaa1;hpb=1ebeaaa7f0c3f0f94f28377404c52a11cca50d86;p=sliver-openvswitch.git diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index f16005cec..7ccff438c 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -58,6 +58,7 @@ #include "unaligned.h" #include "unixctl.h" #include "vlog.h" +#include "bundles.h" VLOG_DEFINE_THIS_MODULE(ofproto); @@ -125,7 +126,7 @@ struct ofoperation { /* OFOPERATION_MODIFY, OFOPERATION_REPLACE: The old actions, if the actions * are changing. */ - struct rule_actions *actions; + const struct rule_actions *actions; /* OFOPERATION_DELETE. */ enum ofp_flow_removed_reason reason; /* Reason flow was removed. */ @@ -259,7 +260,6 @@ 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 *rule, enum ofputil_flow_mod_flags flag); @@ -1019,10 +1019,12 @@ ofproto_port_set_bfd(struct ofproto *ofproto, ofp_port_t ofp_port, } } -/* Populates 'status' with key value pairs indicating the status of the BFD - * session on 'ofp_port'. This information is intended to be populated in the - * OVS database. Has no effect if 'ofp_port' is not na OpenFlow port in - * 'ofproto'. */ +/* Populates 'status' with the status of BFD on 'ofport'. Returns 0 on + * success. Returns a negative number if there is no status change since + * last update. Returns a positive errno otherwise. Has no effect if + * 'ofp_port' is not an OpenFlow port in 'ofproto'. + * + * The caller must provide and own '*status'. */ int ofproto_port_get_bfd_status(struct ofproto *ofproto, ofp_port_t ofp_port, struct smap *status) @@ -1310,9 +1312,9 @@ ofproto_destroy__(struct ofproto *ofproto) ovs_assert(list_is_empty(&ofproto->pending)); destroy_rule_executes(ofproto); - guarded_list_destroy(&ofproto->rule_executes); - delete_group(ofproto, OFPG_ALL); + + guarded_list_destroy(&ofproto->rule_executes); ovs_rwlock_destroy(&ofproto->groups_rwlock); hmap_destroy(&ofproto->groups); @@ -1372,7 +1374,8 @@ ofproto_destroy(struct ofproto *p) } p->ofproto_class->destruct(p); - ofproto_destroy__(p); + /* Destroying rules is deferred, must have 'ofproto' around for them. */ + ovsrcu_postpone(ofproto_destroy__, p); } /* Destroys the datapath with the respective 'name' and 'type'. With the Linux @@ -1939,7 +1942,7 @@ 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) { - struct rule_actions *actions = rule_get_actions(rule); + const struct rule_actions *actions = rule_get_actions(rule); must_add = !ofpacts_equal(actions->ofpacts, actions->ofpacts_len, ofpacts, ofpacts_len); } else { @@ -1973,14 +1976,13 @@ ofproto_flow_mod(struct ofproto *ofproto, struct ofputil_flow_mod *fm) if (fm->command == OFPFC_MODIFY_STRICT && fm->table_id != OFPTT_ALL && !(fm->flags & OFPUTIL_FF_RESET_COUNTS)) { struct oftable *table = &ofproto->tables[fm->table_id]; - struct cls_rule match_rule; struct rule *rule; bool done = false; - cls_rule_init(&match_rule, &fm->match, fm->priority); fat_rwlock_rdlock(&table->cls.rwlock); - rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls, - &match_rule)); + rule = rule_from_cls_rule(classifier_find_match_exactly(&table->cls, + &fm->match, + fm->priority)); if (rule) { /* Reading many of the rule fields and writing on 'modified' * requires the rule->mutex. Also, rule->actions may change @@ -2642,6 +2644,23 @@ update_mtu(struct ofproto *p, struct ofport *port) } } +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_destroy(rule_get_actions(rule)); + ovs_mutex_destroy(&rule->mutex); + rule->ofproto->ofproto_class->rule_dealloc(rule); +} + +static void +rule_destroy_cb(struct rule *rule) +{ + rule->ofproto->ofproto_class->rule_destruct(rule); + ofproto_rule_destroy__(rule); +} + void ofproto_rule_ref(struct rule *rule) { @@ -2650,60 +2669,47 @@ ofproto_rule_ref(struct rule *rule) } } +/* Decrements 'rule''s ref_count and schedules 'rule' to be destroyed if the + * ref_count reaches 0. + * + * Use of RCU allows short term use (between RCU quiescent periods) without + * keeping a reference. A reference must be taken if the rule needs to + * stay around accross the RCU quiescent periods. */ void ofproto_rule_unref(struct rule *rule) { if (rule && ovs_refcount_unref(&rule->ref_count) == 1) { - rule->ofproto->ofproto_class->rule_destruct(rule); - ofproto_rule_destroy__(rule); + ovsrcu_postpone(rule_destroy_cb, rule); } } -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_destroy(rule_get_actions(rule)); - ovs_mutex_destroy(&rule->mutex); - rule->ofproto->ofproto_class->rule_dealloc(rule); -} - static uint32_t get_provider_meter_id(const struct ofproto *, uint32_t of_meter_id); -/* Creates and returns a new 'struct rule_actions', with a ref_count of 1, - * whose actions are a copy of from the 'ofpacts_len' bytes of 'ofpacts'. */ -struct rule_actions * +/* Creates and returns a new 'struct rule_actions', whose actions are a copy + * of from the 'ofpacts_len' bytes of 'ofpacts'. */ +const struct rule_actions * rule_actions_create(const struct ofproto *ofproto, const struct ofpact *ofpacts, size_t ofpacts_len) { struct rule_actions *actions; - actions = xmalloc(sizeof *actions); - actions->ofpacts = xmemdup(ofpacts, ofpacts_len); + actions = xmalloc(sizeof *actions + ofpacts_len); actions->ofpacts_len = ofpacts_len; actions->provider_meter_id = get_provider_meter_id(ofproto, ofpacts_get_meter(ofpacts, ofpacts_len)); + memcpy(actions->ofpacts, ofpacts, ofpacts_len); return actions; } -static void -rule_actions_destroy_cb(struct rule_actions *actions) -{ - free(actions->ofpacts); - free(actions); -} - -/* Decrements 'actions''s ref_count and frees 'actions' if the ref_count - * reaches 0. */ +/* Free the actions after the RCU quiescent period is reached. */ void -rule_actions_destroy(struct rule_actions *actions) +rule_actions_destroy(const struct rule_actions *actions) { if (actions) { - ovsrcu_postpone(rule_actions_destroy_cb, actions); + ovsrcu_postpone(free, CONST_CAST(struct rule_actions *, actions)); } } @@ -3647,7 +3653,7 @@ handle_flow_stats_request(struct ofconn *ofconn, long long int now = time_msec(); struct ofputil_flow_stats fs; long long int created, used, modified; - struct rule_actions *actions; + const struct rule_actions *actions; enum ofputil_flow_mod_flags flags; ovs_mutex_lock(&rule->mutex); @@ -3688,7 +3694,7 @@ static void flow_stats_ds(struct rule *rule, struct ds *results) { uint64_t packet_count, byte_count; - struct rule_actions *actions; + const struct rule_actions *actions; long long int created, used; rule->ofproto->ofproto_class->rule_get_stats(rule, &packet_count, @@ -3743,20 +3749,22 @@ ofproto_get_netflow_ids(const struct ofproto *ofproto, ofproto->ofproto_class->get_netflow_ids(ofproto, engine_type, engine_id); } -/* Checks the status of CFM configured on 'ofp_port' within 'ofproto'. Returns - * true if the port's CFM status was successfully stored into '*status'. - * Returns false if the port did not have CFM configured, in which case - * '*status' is indeterminate. +/* Checks the status of CFM configured on 'ofp_port' within 'ofproto'. + * Returns 0 if the port's CFM status was successfully stored into + * '*status'. Returns positive errno if the port did not have CFM + * configured. Returns negative number if there is no status change + * since last update. * - * The caller must provide and owns '*status', and must free 'status->rmps'. */ -bool + * The caller must provide and own '*status', and must free 'status->rmps'. + * '*status' is indeterminate if the return value is non-zero. */ +int ofproto_port_get_cfm_status(const struct ofproto *ofproto, ofp_port_t ofp_port, struct ofproto_cfm_status *status) { struct ofport *ofport = ofproto_get_port(ofproto, ofp_port); - return (ofport - && ofproto->ofproto_class->get_cfm_status - && ofproto->ofproto_class->get_cfm_status(ofport, status)); + return (ofport && ofproto->ofproto_class->get_cfm_status + ? ofproto->ofproto_class->get_cfm_status(ofport, status) + : EOPNOTSUPP); } static enum ofperr @@ -3946,7 +3954,8 @@ is_flow_deletion_pending(const struct ofproto *ofproto, HMAP_FOR_EACH_WITH_HASH (op, hmap_node, cls_rule_hash(cls_rule, table_id), &ofproto->deletions) { - if (cls_rule_equal(cls_rule, &op->rule->cr)) { + if (op->rule->table_id == table_id + && cls_rule_equal(cls_rule, &op->rule->cr)) { return true; } } @@ -4228,7 +4237,7 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn, reset_counters = (fm->flags & OFPUTIL_FF_RESET_COUNTS) != 0; if (actions_changed || reset_counters) { - struct rule_actions *new_actions; + const struct rule_actions *new_actions; op->actions = rule_get_actions(rule); new_actions = rule_actions_create(ofproto, @@ -5923,6 +5932,69 @@ handle_table_mod(struct ofconn *ofconn, const struct ofp_header *oh) return table_mod(ofproto, &tm); } +static enum ofperr +handle_bundle_control(struct ofconn *ofconn, const struct ofp_header *oh) +{ + enum ofperr error; + struct ofputil_bundle_ctrl_msg bctrl; + struct ofpbuf *buf; + struct ofputil_bundle_ctrl_msg reply; + + error = ofputil_decode_bundle_ctrl(oh, &bctrl); + if (error) { + return error; + } + reply.flags = 0; + reply.bundle_id = bctrl.bundle_id; + + switch (bctrl.type) { + case OFPBCT_OPEN_REQUEST: + error = ofp_bundle_open(ofconn, bctrl.bundle_id, bctrl.flags); + reply.type = OFPBCT_OPEN_REPLY; + break; + case OFPBCT_CLOSE_REQUEST: + error = ofp_bundle_close(ofconn, bctrl.bundle_id, bctrl.flags); + reply.type = OFPBCT_CLOSE_REPLY;; + break; + case OFPBCT_COMMIT_REQUEST: + error = ofp_bundle_commit(ofconn, bctrl.bundle_id, bctrl.flags); + reply.type = OFPBCT_COMMIT_REPLY; + break; + case OFPBCT_DISCARD_REQUEST: + error = ofp_bundle_discard(ofconn, bctrl.bundle_id); + reply.type = OFPBCT_DISCARD_REPLY; + break; + + case OFPBCT_OPEN_REPLY: + case OFPBCT_CLOSE_REPLY: + case OFPBCT_COMMIT_REPLY: + case OFPBCT_DISCARD_REPLY: + return OFPERR_OFPBFC_BAD_TYPE; + break; + } + + if (!error) { + buf = ofputil_encode_bundle_ctrl_reply(oh, &reply); + ofconn_send_reply(ofconn, buf); + } + return error; +} + + +static enum ofperr +handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh) +{ + enum ofperr error; + struct ofputil_bundle_add_msg badd; + + error = ofputil_decode_bundle_add(oh, &badd); + if (error) { + return error; + } + + return ofp_bundle_add_message(ofconn, &badd); +} + static enum ofperr handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) OVS_EXCLUDED(ofproto_mutex) @@ -6055,6 +6127,12 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPTYPE_QUEUE_GET_CONFIG_REQUEST: return handle_queue_get_config_request(ofconn, oh); + case OFPTYPE_BUNDLE_CONTROL: + return handle_bundle_control(ofconn, oh); + + case OFPTYPE_BUNDLE_ADD_MESSAGE: + return handle_bundle_add(ofconn, oh); + case OFPTYPE_HELLO: case OFPTYPE_ERROR: case OFPTYPE_FEATURES_REPLY: @@ -6326,7 +6404,7 @@ ofopgroup_complete(struct ofopgroup *group) rule->hard_timeout = op->hard_timeout; ovs_mutex_unlock(&rule->mutex); if (op->actions) { - struct rule_actions *old_actions; + const struct rule_actions *old_actions; ovs_mutex_lock(&rule->mutex); old_actions = rule_get_actions(rule); @@ -6902,7 +6980,7 @@ oftable_insert_rule(struct rule *rule) { struct ofproto *ofproto = rule->ofproto; struct oftable *table = &ofproto->tables[rule->table_id]; - struct rule_actions *actions; + const struct rule_actions *actions; bool may_expire; ovs_mutex_lock(&rule->mutex); @@ -6984,25 +7062,30 @@ ofproto_unixctl_init(void) void ofproto_get_vlan_usage(struct ofproto *ofproto, unsigned long int *vlan_bitmap) { + struct match match; + struct cls_rule target; const struct oftable *oftable; + match_init_catchall(&match); + match_set_vlan_vid_masked(&match, htons(VLAN_CFI), htons(VLAN_CFI)); + cls_rule_init(&target, &match, 0); + free(ofproto->vlan_bitmap); ofproto->vlan_bitmap = bitmap_allocate(4096); ofproto->vlans_changed = false; OFPROTO_FOR_EACH_TABLE (oftable, ofproto) { - const struct cls_subtable *table; + struct cls_cursor cursor; + struct rule *rule; fat_rwlock_rdlock(&oftable->cls.rwlock); - HMAP_FOR_EACH (table, hmap_node, &oftable->cls.subtables) { - if (minimask_get_vid_mask(&table->mask) == VLAN_VID_MASK) { - const struct cls_rule *rule; - - HMAP_FOR_EACH (rule, hmap_node, &table->rules) { - uint16_t vid = miniflow_get_vid(&rule->match.flow); - bitmap_set1(vlan_bitmap, vid); - bitmap_set1(ofproto->vlan_bitmap, vid); - } + cls_cursor_init(&cursor, &oftable->cls, &target); + CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { + if (minimask_get_vid_mask(&rule->cr.match.mask) == VLAN_VID_MASK) { + uint16_t vid = miniflow_get_vid(&rule->cr.match.flow); + + bitmap_set1(vlan_bitmap, vid); + bitmap_set1(ofproto->vlan_bitmap, vid); } } fat_rwlock_unlock(&oftable->cls.rwlock);