Commit message: ofproto: Fix OVS crash when reverting old flows in bundle commit

During bundle commit flows which are added in bundle are applied
to ofproto in-order. In case if a flow cannot be added (e.g. flow
action is go-to group id which does not exist), OVS tries to
revert back all previous flows which were successfully applied
from the same bundle. This is possible since OVS maintains list
of old flows which were replaced by flows from the bundle.

While reinserting old flows ovs asserts due to check on rule
state != RULE_INITIALIZED.  This will work only for new flows, but
for old flow the rule state will be RULE_REMOVED. This is causing
an assert and OVS crash.

The ovs assert check should be modified to != RULE_INSERTED to prevent
any existing rule being re-inserted and allow new rules and old rules
(in case of revert) to get inserted.

Here is an example to trigger the assert:

$ ovs-vsctl add-br br-test -- set Bridge br-test datapath_type=netdev

$ cat flows.txt
flow add table=1,priority=0,in_port=2,actions=NORMAL
flow add table=1,priority=0,in_port=3,actions=NORMAL

$ ovs-ofctl dump-flows -OOpenflow13 br-test
 cookie=0x0, duration=2.465s, table=1, n_packets=0, n_bytes=0, priority=0,in_port=2 actions=NORMAL
 cookie=0x0, duration=2.465s, table=1, n_packets=0, n_bytes=0, priority=0,in_port=3 actions=NORMAL

$ cat flow-modify.txt
flow modify table=1,priority=0,in_port=2,actions=drop
flow modify table=1,priority=0,in_port=3,actions=group:10

$ ovs-ofctl bundle br-test flow-modify.txt -OOpenflow13

First flow rule will be modified since it is a valid rule. However second
rule is invalid since no group with id 10 exists. Bundle commit tries to
revert (insert) the first rule to old flow which results in ovs_assert at
ofproto_rule_insert__() since old rule->state = RULE_REMOVED.

Signed-off-by: Vishal Deep Ajmera <vishal.deep.ajmera@ericsson.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
CVE: CVE-2018-17205
CWE: CWE-617
Vulnerability description: An issue was discovered in Open vSwitch (OvS) 2.7.x through 2.7.6, affecting ofproto_rule_insert__ in ofproto/ofproto.c. During bundle commit, flows that are added in a bundle are applied to ofproto in order. If a flow cannot be added (e.g., the flow action is a go-to for a group id that does not exist), OvS tries to revert back all previous flows that were successfully applied from the same bundle. This is possible since OvS maintains list of old flows that were replaced by flows from the bundle. While reinserting old flows, OvS has an assertion failure due to a check on rule state != RULE_INITIALIZED. This would work for new flows, but for an old flow the rule state is RULE_REMOVED. The assertion failure causes an OvS crash.

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    const struct ofproto_class *class;
    struct ofproto *ofproto;
    int error;
    int i;

    *ofprotop = NULL;

    datapath_type = ofproto_normalize_type(datapath_type);
    class = ofproto_class_find__(datapath_type);
    if (!class) {
        VLOG_WARN("could not create datapath %s of unknown type %s",
                  datapath_name, datapath_type);
        return EAFNOSUPPORT;
    }

    ofproto = class->alloc();
    if (!ofproto) {
        VLOG_ERR("failed to allocate datapath %s of type %s",
                 datapath_name, datapath_type);
        return ENOMEM;
    }

    /* Initialize. */
    ovs_mutex_lock(&ofproto_mutex);
    memset(ofproto, 0, sizeof *ofproto);
    ofproto->ofproto_class = class;
    ofproto->name = xstrdup(datapath_name);
    ofproto->type = xstrdup(datapath_type);
    hmap_insert(&all_ofprotos, &ofproto->hmap_node,
                hash_string(ofproto->name, 0));
    ofproto->datapath_id = 0;
    ofproto->forward_bpdu = false;
    ofproto->fallback_dpid = pick_fallback_dpid();
    ofproto->mfr_desc = NULL;
    ofproto->hw_desc = NULL;
    ofproto->sw_desc = NULL;
    ofproto->serial_desc = NULL;
    ofproto->dp_desc = NULL;
    ofproto->frag_handling = OFPUTIL_FRAG_NORMAL;
    hmap_init(&ofproto->ports);
    hmap_init(&ofproto->ofport_usage);
    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;
    ofproto->tables_version = OVS_VERSION_MIN;
    hindex_init(&ofproto->cookies);
    hmap_init(&ofproto->learned_cookies);
    ovs_list_init(&ofproto->expirable);
    ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name);
    ofproto->min_mtu = INT_MAX;
    cmap_init(&ofproto->groups);
    ovs_mutex_unlock(&ofproto_mutex);
    ofproto->ogf.types = 0xf;
    ofproto->ogf.capabilities = OFPGFC_CHAINING | OFPGFC_SELECT_LIVENESS |
                                OFPGFC_SELECT_WEIGHT;
    for (i = 0; i < 4; i++) {
        ofproto->ogf.max_groups[i] = OFPG_MAX;
        ofproto->ogf.ofpacts[i] = (UINT64_C(1) << N_OFPACTS) - 1;
    }
    ovsrcu_set(&ofproto->metadata_tab, tun_metadata_alloc(NULL));

    ovs_mutex_init(&ofproto->vl_mff_map.mutex);
    cmap_init(&ofproto->vl_mff_map.cmap);

    error = ofproto->ofproto_class->construct(ofproto);
    if (error) {
        VLOG_ERR("failed to open datapath %s: %s",
                 datapath_name, ovs_strerror(error));
        ovs_mutex_lock(&ofproto_mutex);
        connmgr_destroy(ofproto->connmgr);
        ofproto->connmgr = NULL;
        ovs_mutex_unlock(&ofproto_mutex);
        ofproto_destroy__(ofproto);
        return error;
    }

    /* Check that hidden tables, if any, are at the end. */
    ovs_assert(ofproto->n_tables);
    for (i = 0; i + 1 < ofproto->n_tables; i++) {
        enum oftable_flags flags = ofproto->tables[i].flags;
        enum oftable_flags next_flags = ofproto->tables[i + 1].flags;

        ovs_assert(!(flags & OFTABLE_HIDDEN) || next_flags & OFTABLE_HIDDEN);
    }

    ofproto->datapath_id = pick_datapath_id(ofproto);
    init_ports(ofproto);

    /* Initialize meters table. */
    if (ofproto->ofproto_class->meter_get_features) {
        ofproto->ofproto_class->meter_get_features(ofproto,
                                                   &ofproto->meter_features);
    } else {
        memset(&ofproto->meter_features, 0, sizeof ofproto->meter_features);
    }
    ofproto->meters = xzalloc((ofproto->meter_features.max_meters + 1)
                              * sizeof(struct meter *));

    /* Set the initial tables version. */
    ofproto_bump_tables_version(ofproto);

    *ofprotop = ofproto;
    return 0;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct oftable *table;

    /* This will flush all datapath flows. */
    if (ofproto->ofproto_class->flush) {
        ofproto->ofproto_class->flush(ofproto);
    }

    /* XXX: There is a small race window here, where new datapath flows can be
     * created by upcall handlers based on the existing flow table.  We can not
     * call ofproto class flush while holding 'ofproto_mutex' to prevent this,
     * as then we could deadlock on syncing with the handler threads waiting on
     * the same mutex. */

    ovs_mutex_lock(&ofproto_mutex);
    OFPROTO_FOR_EACH_TABLE (table, ofproto) {
        struct rule_collection rules;
        struct rule *rule;

        if (table->flags & OFTABLE_HIDDEN) {
            continue;
        }

        rule_collection_init(&rules);

        CLS_FOR_EACH (rule, cr, &table->cls) {
            rule_collection_add(&rules, rule);
        }
        delete_flows__(&rules, OFPRR_DELETE, NULL);
    }
    /* XXX: Concurrent handler threads may insert new learned flows based on
     * learn actions of the now deleted flows right after we release
     * 'ofproto_mutex'. */
    ovs_mutex_unlock(&ofproto_mutex);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct oftable *table;

    cmap_destroy(&ofproto->groups);

    hmap_remove(&all_ofprotos, &ofproto->hmap_node);

    free(ofproto->name);
    free(ofproto->type);
    free(ofproto->mfr_desc);
    free(ofproto->hw_desc);
    free(ofproto->sw_desc);
    free(ofproto->serial_desc);
    free(ofproto->dp_desc);
    hmap_destroy(&ofproto->ports);
    hmap_destroy(&ofproto->ofport_usage);
    shash_destroy(&ofproto->port_by_name);
    simap_destroy(&ofproto->ofp_requests);

    OFPROTO_FOR_EACH_TABLE (table, ofproto) {
        oftable_destroy(table);
    }
    free(ofproto->tables);

    ovs_mutex_lock(&ofproto->vl_mff_map.mutex);
    mf_vl_mff_map_clear(&ofproto->vl_mff_map, true);
    ovs_mutex_unlock(&ofproto->vl_mff_map.mutex);
    cmap_destroy(&ofproto->vl_mff_map.cmap);
    ovs_mutex_destroy(&ofproto->vl_mff_map.mutex);
    tun_metadata_free(ovsrcu_get_protected(struct tun_table *,
                                           &ofproto->metadata_tab));

    ovs_assert(hindex_is_empty(&ofproto->cookies));
    hindex_destroy(&ofproto->cookies);

    ovs_assert(hmap_is_empty(&ofproto->learned_cookies));
    hmap_destroy(&ofproto->learned_cookies);

    ofproto->ofproto_class->dealloc(ofproto);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    ovsrcu_postpone(ofproto_destroy__, ofproto);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofport *ofport, *next_ofport;
    struct ofport_usage *usage;

    if (!p) {
        return;
    }

    if (p->meters) {
        meter_delete(p, 1, p->meter_features.max_meters);
        p->meter_features.max_meters = 0;
        free(p->meters);
        p->meters = NULL;
    }

    ofproto_flush__(p);
    HMAP_FOR_EACH_SAFE (ofport, next_ofport, hmap_node, &p->ports) {
        ofport_destroy(ofport, del);
    }

    HMAP_FOR_EACH_POP (usage, hmap_node, &p->ofport_usage) {
        free(usage);
    }

    p->ofproto_class->destruct(p, del);

    /* We should not postpone this because it involves deleting a listening
     * socket which we may want to reopen soon. 'connmgr' may be used by other
     * threads only if they take the ofproto_mutex and read a non-NULL
     * 'ofproto->connmgr'. */
    ovs_mutex_lock(&ofproto_mutex);
    connmgr_destroy(p->connmgr);
    p->connmgr = NULL;
    ovs_mutex_unlock(&ofproto_mutex);

    /* Destroying rules is deferred, must have 'ofproto' around for them. */
    ovsrcu_postpone(ofproto_destroy_defer__, p);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    const struct rule *rule;
    bool must_add;

    /* First do a cheap check whether the rule we're looking for already exists
     * with the actions that we want.  If it does, then we're done. */
    rule = rule_from_cls_rule(classifier_find_match_exactly(
                                  &ofproto->tables[0].cls, match, priority,
                                  OVS_VERSION_MAX));
    if (rule) {
        const struct rule_actions *actions = rule_get_actions(rule);
        must_add = !ofpacts_equal(actions->ofpacts, actions->ofpacts_len,
                                  ofpacts, ofpacts_len);
    } else {
        must_add = true;
    }

    /* If there's no such rule or the rule doesn't have the actions we want,
     * fall back to a executing a full flow mod.  We can't optimize this at
     * all because we didn't take enough locks above to ensure that the flow
     * table didn't already change beneath us.  */
    if (must_add) {
        simple_flow_mod(ofproto, match, priority, ofpacts, ofpacts_len,
                        OFPFC_MODIFY_STRICT);
    }
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    return handle_flow_mod__(ofproto, fm, NULL);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    ovs_mutex_lock(&ofproto_mutex);
    remove_rule_rcu__(rule);
    ovs_mutex_unlock(&ofproto_mutex);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct rule **orig_rules = rules;

    if (*rules) {
        struct ofproto *ofproto = rules[0]->ofproto;
        unsigned long tables[BITMAP_N_LONGS(256)];
        struct rule *rule;
        size_t table_id;

        memset(tables, 0, sizeof tables);

        ovs_mutex_lock(&ofproto_mutex);
        while ((rule = *rules++)) {
            /* Defer once for each new table.  This defers the subtable cleanup
             * until later, so that when removing large number of flows the
             * operation is faster. */
            if (!bitmap_is_set(tables, rule->table_id)) {
                struct classifier *cls = &ofproto->tables[rule->table_id].cls;

                bitmap_set1(tables, rule->table_id);
                classifier_defer(cls);
            }
            remove_rule_rcu__(rule);
        }

        BITMAP_FOR_EACH_1(table_id, 256, tables) {
            struct classifier *cls = &ofproto->tables[table_id].cls;

            classifier_publish(cls);
        }
        ovs_mutex_unlock(&ofproto_mutex);
    }

    free(orig_rules);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    ovs_mutex_lock(&ofproto_mutex);
    remove_group_rcu__(group);
    ovs_mutex_unlock(&ofproto_mutex);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    ovs_mutex_lock(&ofproto_mutex);
    for (struct ofgroup **g = groups; *g; g++) {
        remove_group_rcu__(*g);
    }
    ovs_mutex_unlock(&ofproto_mutex);
    free(groups);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto *p = ofconn_get_ofproto(ofconn);
    struct ofputil_packet_out po;
    struct ofproto_packet_out opo;
    uint64_t ofpacts_stub[1024 / 8];
    struct ofpbuf ofpacts;
    enum ofperr error;

    COVERAGE_INC(ofproto_packet_out);

    error = reject_slave_controller(ofconn);
    if (error) {
        return error;
    }

    /* Decode message. */
    ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
    error = ofputil_decode_packet_out(&po, oh, &ofpacts);
    if (error) {
        ofpbuf_uninit(&ofpacts);
        return error;
    }

    po.ofpacts = ofpbuf_steal_data(&ofpacts);   /* Move to heap. */
    error = ofproto_packet_out_init(p, ofconn, &opo, &po);
    if (error) {
        free(po.ofpacts);
        return error;
    }

    ovs_mutex_lock(&ofproto_mutex);
    opo.version = p->tables_version;
    error = ofproto_packet_out_start(p, &opo);
    if (!error) {
        ofproto_packet_out_finish(p, &opo);
    }
    ovs_mutex_unlock(&ofproto_mutex);

    ofproto_packet_out_uninit(&opo);
    return error;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_flow_stats_request fsr;
    struct rule_criteria criteria;
    struct rule_collection rules;
    struct ovs_list replies;
    enum ofperr error;

    error = ofputil_decode_flow_stats_request(&fsr, request,
                                              ofproto_get_tun_tab(ofproto),
                                              &ofproto->vl_mff_map);
    if (error) {
        return error;
    }

    rule_criteria_init(&criteria, fsr.table_id, &fsr.match, 0, OVS_VERSION_MAX,
                       fsr.cookie, fsr.cookie_mask, fsr.out_port,
                       fsr.out_group);

    ovs_mutex_lock(&ofproto_mutex);
    error = collect_rules_loose(ofproto, &criteria, &rules);
    rule_criteria_destroy(&criteria);
    if (!error) {
        rule_collection_ref(&rules);
    }
    ovs_mutex_unlock(&ofproto_mutex);

    if (error) {
        return error;
    }

    ofpmp_init(&replies, request);
    struct rule *rule;
    RULE_COLLECTION_FOR_EACH (rule, &rules) {
        long long int now = time_msec();
        struct ofputil_flow_stats fs;
        long long int created, used, modified;
        const struct rule_actions *actions;
        enum ofputil_flow_mod_flags flags;

        ovs_mutex_lock(&rule->mutex);
        fs.cookie = rule->flow_cookie;
        fs.idle_timeout = rule->idle_timeout;
        fs.hard_timeout = rule->hard_timeout;
        fs.importance = rule->importance;
        created = rule->created;
        modified = rule->modified;
        actions = rule_get_actions(rule);
        flags = rule->flags;
        ovs_mutex_unlock(&rule->mutex);

        ofproto->ofproto_class->rule_get_stats(rule, &fs.packet_count,
                                               &fs.byte_count, &used);

        minimatch_expand(&rule->cr.match, &fs.match);
        fs.table_id = rule->table_id;
        calc_duration(created, now, &fs.duration_sec, &fs.duration_nsec);
        fs.priority = rule->cr.priority;
        fs.idle_age = age_secs(now - used);
        fs.hard_age = age_secs(now - modified);
        fs.ofpacts = actions->ofpacts;
        fs.ofpacts_len = actions->ofpacts_len;

        fs.flags = flags;
        ofputil_append_flow_stats_reply(&fs, &replies,
                                        ofproto_get_tun_tab(ofproto));
    }

    rule_collection_unref(&rules);
    rule_collection_destroy(&rules);

    ofconn_send_replies(ofconn, &replies);

    return 0;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct oftable *table;
    struct cls_rule cr;
    uint8_t table_id;
    enum ofperr error;

    if (!check_table_id(ofproto, fm->table_id)) {
        return OFPERR_OFPBRC_BAD_TABLE_ID;
    }

    /* Pick table. */
    if (fm->table_id == 0xff) {
        if (ofproto->ofproto_class->rule_choose_table) {
            error = ofproto->ofproto_class->rule_choose_table(ofproto,
                                                              &fm->match,
                                                              &table_id);
            if (error) {
                return error;
            }
            ovs_assert(table_id < ofproto->n_tables);
        } else {
            table_id = 0;
        }
    } else if (fm->table_id < ofproto->n_tables) {
        table_id = fm->table_id;
    } else {
        return OFPERR_OFPBRC_BAD_TABLE_ID;
    }

    table = &ofproto->tables[table_id];
    if (table->flags & OFTABLE_READONLY
        && !(fm->flags & OFPUTIL_FF_NO_READONLY)) {
        return OFPERR_OFPBRC_EPERM;
    }

    if (!(fm->flags & OFPUTIL_FF_HIDDEN_FIELDS)
        && !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;
    }

    if (!ofm->temp_rule) {
        cls_rule_init(&cr, &fm->match, fm->priority);

        /* Allocate new rule.  Destroys 'cr'. */
        error = ofproto_rule_create(ofproto, &cr, table - ofproto->tables,
                                    fm->new_cookie, fm->idle_timeout,
                                    fm->hard_timeout, fm->flags,
                                    fm->importance, fm->ofpacts,
                                    fm->ofpacts_len,
                                    fm->match.flow.tunnel.metadata.present.map,
                                    fm->ofpacts_tlv_bitmap, &ofm->temp_rule);
        if (error) {
            return error;
        }

        get_conjunctions(fm, &ofm->conjs, &ofm->n_conjs);
    }
    return 0;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    /* Reject flow mods that do not look like they were generated by a learn
     * action. */
    if (fm->command != OFPFC_MODIFY_STRICT || fm->table_id == OFPTT_ALL
        || fm->flags & OFPUTIL_FF_RESET_COUNTS
        || fm->buffer_id != UINT32_MAX) {
        return OFPERR_OFPFMFC_UNKNOWN;
    }

    /* Check if the rule already exists, and we can get a reference to it. */
    struct oftable *table = &ofproto->tables[fm->table_id];
    struct rule *rule;

    rule = rule_from_cls_rule(classifier_find_match_exactly(
                                  &table->cls, &fm->match, fm->priority,
                                  OVS_VERSION_MAX));
    if (rule) {
        /* Check if the rule's attributes match as well. */
        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->importance == fm->importance
            && rule->flags == (fm->flags & OFPUTIL_FF_STATE)
            && (!fm->modify_cookie || (fm->new_cookie == rule->flow_cookie))
            && ofpacts_equal(fm->ofpacts, fm->ofpacts_len,
                             actions->ofpacts, actions->ofpacts_len)) {
            /* Rule already exists and need not change, except for the modified
             * timestamp.  Get a reference to the existing rule. */
            ovs_mutex_unlock(&rule->mutex);
            if (!ofproto_rule_try_ref(rule)) {
                rule = NULL; /* Pretend it did not exist. */
            }
        } else {
            ovs_mutex_unlock(&rule->mutex);
            rule = NULL;
        }
    }

    return ofproto_flow_mod_init(ofproto, ofm, fm, rule);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    rule_criteria_init(&ofm->criteria, fm->table_id, &fm->match, fm->priority,
                       OVS_VERSION_MAX, fm->cookie, fm->cookie_mask, OFPP_ANY,
                       OFPG_ANY);
    rule_criteria_require_rw(&ofm->criteria,
                             (fm->flags & OFPUTIL_FF_NO_READONLY) != 0);
    /* Must create a new flow in advance for the case that no matches are
     * found.  Also used for template for multiple modified flows. */
    add_flow_init(ofproto, ofm, fm);

    return 0;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    rule_criteria_init(&ofm->criteria, fm->table_id, &fm->match, fm->priority,
                       OVS_VERSION_MAX, fm->cookie, fm->cookie_mask,
                       fm->out_port, fm->out_group);
    rule_criteria_require_rw(&ofm->criteria,
                             (fm->flags & OFPUTIL_FF_NO_READONLY) != 0);
    return 0;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofputil_flow_removed fr;
    long long int used;

    minimatch_expand(&rule->cr.match, &fr.match);
    fr.priority = rule->cr.priority;

    /* Synchronize with connmgr_destroy() calls to prevent connmgr disappearing
     * while we use it. */
    ovs_mutex_lock(&ofproto_mutex);
    struct connmgr *connmgr = rule->ofproto->connmgr;
    if (!connmgr) {
        ovs_mutex_unlock(&ofproto_mutex);
        return;
    }

    fr.cookie = rule->flow_cookie;
    fr.reason = rule->removed_reason;
    fr.table_id = rule->table_id;
    calc_duration(rule->created, time_msec(),
                  &fr.duration_sec, &fr.duration_nsec);
    ovs_mutex_lock(&rule->mutex);
    fr.idle_timeout = rule->idle_timeout;
    fr.hard_timeout = rule->hard_timeout;
    ovs_mutex_unlock(&rule->mutex);
    rule->ofproto->ofproto_class->rule_get_stats(rule, &fr.packet_count,
                                                 &fr.byte_count, &used);
    connmgr_send_flow_removed(connmgr, &fr);
    ovs_mutex_unlock(&ofproto_mutex);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_flow_mod fm;
    uint64_t ofpacts_stub[1024 / 8];
    struct ofpbuf ofpacts;
    enum ofperr error;

    error = reject_slave_controller(ofconn);
    if (error) {
        return error;
    }

    ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
    error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn),
                                    ofproto_get_tun_tab(ofproto),
                                    &ofproto->vl_mff_map, &ofpacts,
                                    u16_to_ofp(ofproto->max_ports),
                                    ofproto->n_tables);
    if (!error) {
        struct openflow_mod_requester req = { ofconn, oh };
        error = handle_flow_mod__(ofproto, &fm, &req);
    }

    ofpbuf_uninit(&ofpacts);
    return error;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto_flow_mod ofm;
    enum ofperr error;

    error = ofproto_flow_mod_init(ofproto, &ofm, fm, NULL);
    if (error) {
        return error;
    }

    ovs_mutex_lock(&ofproto_mutex);
    ofm.version = ofproto->tables_version + 1;
    error = ofproto_flow_mod_start(ofproto, &ofm);
    if (!error) {
        ofproto_bump_tables_version(ofproto);
        ofproto_flow_mod_finish(ofproto, &ofm, req);
        ofmonitor_flush(ofproto->connmgr);
    }
    ovs_mutex_unlock(&ofproto_mutex);

    return error;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);

    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));

    struct ofmonitor **monitors = NULL;
    size_t allocated_monitors = 0;
    size_t n_monitors = 0;

    enum ofperr error;

    ovs_mutex_lock(&ofproto_mutex);
    for (;;) {
        struct ofputil_flow_monitor_request request;
        struct ofmonitor *m;
        int retval;

        retval = ofputil_decode_flow_monitor_request(&request, &b);
        if (retval == EOF) {
            break;
        } else if (retval) {
            error = retval;
            goto error;
        }

        if (request.table_id != 0xff
            && request.table_id >= ofproto->n_tables) {
            error = OFPERR_OFPBRC_BAD_TABLE_ID;
            goto error;
        }

        error = ofmonitor_create(&request, ofconn, &m);
        if (error) {
            goto error;
        }

        if (n_monitors >= allocated_monitors) {
            monitors = x2nrealloc(monitors, &allocated_monitors,
                                  sizeof *monitors);
        }
        monitors[n_monitors++] = m;
    }

    struct rule_collection rules;
    rule_collection_init(&rules);
    for (size_t i = 0; i < n_monitors; i++) {
        ofproto_collect_ofmonitor_initial_rules(monitors[i], &rules);
    }

    struct ovs_list replies;
    ofpmp_init(&replies, oh);
    ofmonitor_compose_refresh_updates(&rules, &replies);
    ovs_mutex_unlock(&ofproto_mutex);

    rule_collection_destroy(&rules);

    ofconn_send_replies(ofconn, &replies);
    free(monitors);

    return 0;

error:
    for (size_t i = 0; i < n_monitors; i++) {
        ofmonitor_destroy(monitors[i]);
    }
    free(monitors);
    ovs_mutex_unlock(&ofproto_mutex);

    return error;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    enum ofperr error;
    uint32_t id;

    id = ofputil_decode_flow_monitor_cancel(oh);

    ovs_mutex_lock(&ofproto_mutex);
    error = flow_monitor_delete(ofconn, id);
    ovs_mutex_unlock(&ofproto_mutex);

    return error;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    uint32_t meter_id = mm->meter.meter_id;
    enum ofperr error = 0;
    uint32_t first, last;

    if (meter_id == OFPM13_ALL) {
        first = 1;
        last = ofproto->meter_features.max_meters;
    } else {
        if (!meter_id || meter_id > ofproto->meter_features.max_meters) {
            return 0;
        }
        first = last = meter_id;
    }

    /* Delete the meters. */
    ovs_mutex_lock(&ofproto_mutex);
    meter_delete(ofproto, first, last);
    ovs_mutex_unlock(&ofproto_mutex);

    return error;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofgroup *group;
    struct ovs_list replies;

    ofpmp_init(&replies, request);
    /* Must exclude modifications to guarantee iterating groups. */
    ovs_mutex_lock(&ofproto_mutex);
    if (group_id == OFPG_ALL) {
        CMAP_FOR_EACH (group, cmap_node, &ofproto->groups) {
            if (versions_visible_in_version(&group->versions,
                                            OVS_VERSION_MAX)) {
                cb(group, &replies);
            }
        }
    } else {
        group = ofproto_group_lookup__(ofproto, group_id, OVS_VERSION_MAX);
        if (group) {
            cb(group, &replies);
        }
    }
    ovs_mutex_unlock(&ofproto_mutex);
    ofconn_send_replies(ofconn, &replies);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto_group_mod ogm;

    ogm.gm.command = OFPGC11_DELETE;
    ogm.gm.group_id = OFPG_ALL;

    ovs_mutex_lock(&ofproto_mutex);
    ogm.version = ofproto->tables_version + 1;
    ofproto_group_mod_start(ofproto, &ogm);
    ofproto_bump_tables_version(ofproto);
    ofproto_group_mod_finish(ofproto, &ogm, NULL);
    ovs_mutex_unlock(&ofproto_mutex);
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofproto_group_mod ogm;
    enum ofperr error;

    error = reject_slave_controller(ofconn);
    if (error) {
        return error;
    }

    error = ofputil_decode_group_mod(oh, &ogm.gm);
    if (error) {
        return error;
    }

    ovs_mutex_lock(&ofproto_mutex);
    ogm.version = ofproto->tables_version + 1;
    error = ofproto_group_mod_start(ofproto, &ogm);
    if (!error) {
        struct openflow_mod_requester req = { ofconn, oh };

        ofproto_bump_tables_version(ofproto);
        ofproto_group_mod_finish(ofproto, &ogm, &req);
        ofmonitor_flush(ofproto->connmgr);
    }
    ovs_mutex_unlock(&ofproto_mutex);

    ofputil_uninit_group_mod(&ogm.gm);

    return error;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    enum ofperr error;

    /* Forward flow mod fields we need later. */
    ofm->command = fm->command;
    ofm->modify_cookie = fm->modify_cookie;

    ofm->modify_may_add_flow = (fm->new_cookie != OVS_BE64_MAX
                                && fm->cookie_mask == htonll(0));
    /* Old flags must be kept when modifying a flow, but we still must
     * honor the reset counts flag if present in the flow mod. */
    ofm->modify_keep_counts = !(fm->flags & OFPUTIL_FF_RESET_COUNTS);

    /* Initialize state needed by ofproto_flow_mod_uninit(). */
    ofm->temp_rule = rule;
    ofm->criteria.version = OVS_VERSION_NOT_REMOVED;
    ofm->conjs = NULL;
    ofm->n_conjs = 0;

    bool check_buffer_id = false;

    switch (ofm->command) {
    case OFPFC_ADD:
        check_buffer_id = true;
        error = add_flow_init(ofproto, ofm, fm);
        break;
    case OFPFC_MODIFY:
        check_buffer_id = true;
        error = modify_flows_init_loose(ofproto, ofm, fm);
        break;
    case OFPFC_MODIFY_STRICT:
        check_buffer_id = true;
        error = modify_flow_init_strict(ofproto, ofm, fm);
        break;
    case OFPFC_DELETE:
        error = delete_flows_init_loose(ofproto, ofm, fm);
        break;
    case OFPFC_DELETE_STRICT:
        error = delete_flows_init_strict(ofproto, ofm, fm);
        break;
    default:
        error = OFPERR_OFPFMFC_BAD_COMMAND;
        break;
    }
    if (!error && check_buffer_id && fm->buffer_id != UINT32_MAX) {
        error = OFPERR_OFPBRC_BUFFER_UNKNOWN;
    }

    if (error) {
        ofproto_flow_mod_uninit(ofm);
    }
    return error;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    enum ofperr error;
    struct ofputil_bundle_add_msg badd;
    struct ofp_bundle_entry *bmsg;
    enum ofptype type;

    error = reject_slave_controller(ofconn);
    if (error) {
        return error;
    }

    error = ofputil_decode_bundle_add(oh, &badd, &type);
    if (error) {
        return error;
    }

    bmsg = ofp_bundle_entry_alloc(type, badd.msg);

    struct ofpbuf ofpacts;
    uint64_t ofpacts_stub[1024 / 8];
    ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);

    if (type == OFPTYPE_PORT_MOD) {
        error = ofputil_decode_port_mod(badd.msg, &bmsg->opm.pm, false);
    } else if (type == OFPTYPE_FLOW_MOD) {
        struct ofputil_flow_mod fm;

        error = ofputil_decode_flow_mod(&fm, badd.msg,
                                        ofconn_get_protocol(ofconn),
                                        ofproto_get_tun_tab(ofproto),
                                        &ofproto->vl_mff_map, &ofpacts,
                                        u16_to_ofp(ofproto->max_ports),
                                        ofproto->n_tables);
        if (!error) {
            error = ofproto_flow_mod_init(ofproto, &bmsg->ofm, &fm, NULL);
        }
    } else if (type == OFPTYPE_GROUP_MOD) {
        error = ofputil_decode_group_mod(badd.msg, &bmsg->ogm.gm);
    } else if (type == OFPTYPE_PACKET_OUT) {
        struct ofputil_packet_out po;

        COVERAGE_INC(ofproto_packet_out);

        /* Decode message. */
        error = ofputil_decode_packet_out(&po, badd.msg, &ofpacts);
        if (!error) {
            po.ofpacts = ofpbuf_steal_data(&ofpacts);   /* Move to heap. */
            error = ofproto_packet_out_init(ofproto, ofconn, &bmsg->opo, &po);
        }
    } else {
        OVS_NOT_REACHED();
    }

    ofpbuf_uninit(&ofpacts);

    if (!error) {
        error = ofp_bundle_add_message(ofconn, badd.bundle_id, badd.flags,
                                       bmsg, oh);
    }

    if (error) {
        ofp_bundle_entry_free(bmsg);
    }

    return error;
}

Project: ovs
File: ofproto.c

    OVS_EXCLUDED(ofproto_mutex)
{
    enum ofperr error = handle_openflow__(ofconn, ofp_msg);

    if (error) {
        ofconn_send_error(ofconn, ofp_msg->data, error);
    }
    COVERAGE_INC(ofproto_recv_openflow);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct classifier *cls = &ofproto->tables[0].cls;
    struct rule *rule;

    /* First do a cheap check whether the rule we're looking for has already
     * been deleted.  If so, then we're done. */
    rule = rule_from_cls_rule(classifier_find_match_exactly(
                                  cls, target, priority, OVS_VERSION_MAX));
    if (!rule) {
        return;
    }

    struct rule_collection rules;

    rule_collection_init(&rules);
    rule_collection_add(&rules, rule);
    delete_flows__(&rules, OFPRR_DELETE, NULL);
    rule_collection_destroy(&rules);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct ofproto *ofproto = group->ofproto;

    ovs_assert(!versions_visible_in_version(&group->versions, OVS_VERSION_MAX));

    cmap_remove(&ofproto->groups, &group->cmap_node,
                hash_int(group->group_id, 0));
    ofproto_group_unref(group);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    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);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    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);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    uint32_t hash = hash_learned_cookie(learn->cookie, learn->table_id);
    struct learned_cookie *c;

    HMAP_FOR_EACH_WITH_HASH (c, u.hmap_node, hash, &ofproto->learned_cookies) {
        if (c->cookie == learn->cookie && c->table_id == learn->table_id) {
            c->n += delta;
            ovs_assert(c->n >= 0);

            if (!c->n) {
                hmap_remove(&ofproto->learned_cookies, &c->u.hmap_node);
                ovs_list_push_back(dead_cookies, &c->u.list_node);
            }

            return;
        }
    }

    ovs_assert(delta > 0);
    c = xmalloc(sizeof *c);
    hmap_insert(&ofproto->learned_cookies, &c->u.hmap_node, hash);
    c->cookie = learn->cookie;
    c->table_id = learn->table_id;
    c->n = delta;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    if (actions->has_learn_with_delete) {
        const struct ofpact_learn *learn;

        for (learn = next_learn_with_delete(actions, NULL); learn;
             learn = next_learn_with_delete(actions, learn)) {
            learned_cookies_update_one__(ofproto, learn, delta, dead_cookies);
        }
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    learned_cookies_update__(ofproto, actions, +1, NULL);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    learned_cookies_update__(ofproto, actions, -1, dead_cookies);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    uint32_t mid;

    mid = ofpacts_get_meter(ofpacts, ofpacts_len);
    if (mid && get_provider_meter_id(ofproto, mid) == UINT32_MAX) {
        return OFPERR_OFPMMFC_INVALID_METER;
    }

    const struct ofpact_group *a;
    OFPACT_FOR_EACH_TYPE_FLATTENED (a, GROUP, ofpacts, ofpacts_len) {
        if (!ofproto_group_exists(ofproto, a->group_id)) {
            return OFPERR_OFPBAC_BAD_OUT_GROUP;
        }
    }

    return 0;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    enum ofperr error;

    error = ofproto_check_ofpacts(ofproto, opo->ofpacts, opo->ofpacts_len);
    if (error) {
        return error;
    }

    return ofproto->ofproto_class->packet_xlate(ofproto, opo);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    ofproto->ofproto_class->packet_xlate_revert(ofproto, opo);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    ofproto->ofproto_class->packet_execute(ofproto, opo);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    hindex_insert(&ofproto->cookies, &rule->cookie_node,
                  hash_cookie(rule->flow_cookie));
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    if (rule_collection_n(rules) > 0) {
        if (rule_collection_n(rules) == 1) {
            ovsrcu_postpone(remove_rule_rcu, rule_collection_rules(rules)[0]);
            rule_collection_init(rules);
        } else {
            ovsrcu_postpone(remove_rules_rcu, rule_collection_detach(rules));
        }
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    if (group_collection_n(groups) > 0) {
        if (group_collection_n(groups) == 1) {
            ovsrcu_postpone(remove_group_rcu,
                            group_collection_groups(groups)[0]);
            group_collection_init(groups);
        } else {
            ovsrcu_postpone(remove_groups_rcu,
                            group_collection_detach(groups));
        }
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    if ((c->table_id == rule->table_id || c->table_id == 0xff)
        && ofproto_rule_has_out_port(rule, c->out_port)
        && ofproto_rule_has_out_group(rule, c->out_group)
        && !((rule->flow_cookie ^ c->cookie) & c->cookie_mask)
        && (!rule_is_hidden(rule) || c->include_hidden)
        && cls_rule_visible_in_version(&rule->cr, c->version)) {
        /* Rule matches all the criteria... */
        if (!rule_is_readonly(rule) || c->include_readonly) {
            /* ...add it. */
            rule_collection_add(rules, rule);
        } else {
            /* ...except it's read-only. */
            ++*n_readonly;
        }
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct oftable *table;
    enum ofperr error = 0;
    size_t n_readonly = 0;

    rule_collection_init(rules);

    if (!check_table_id(ofproto, criteria->table_id)) {
        error = OFPERR_OFPBRC_BAD_TABLE_ID;
        goto exit;
    }

    if (criteria->cookie_mask == OVS_BE64_MAX) {
        struct rule *rule;

        HINDEX_FOR_EACH_WITH_HASH (rule, cookie_node,
                                   hash_cookie(criteria->cookie),
                                   &ofproto->cookies) {
            if (cls_rule_is_loose_match(&rule->cr, &criteria->cr.match)) {
                collect_rule(rule, criteria, rules, &n_readonly);
            }
        }
    } else {
        FOR_EACH_MATCHING_TABLE (table, criteria->table_id, ofproto) {
            struct rule *rule;

            CLS_FOR_EACH_TARGET (rule, cr, &table->cls, &criteria->cr,
                                 criteria->version) {
                collect_rule(rule, criteria, rules, &n_readonly);
            }
        }
    }

exit:
    if (!error && !rule_collection_n(rules) && n_readonly) {
        /* We didn't find any rules to modify.  We did find some read-only
         * rules that we're not allowed to modify, so report that. */
        error = OFPERR_OFPBRC_EPERM;
    }
    if (error) {
        rule_collection_destroy(rules);
    }
    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *old_rule = NULL;
    struct rule *new_rule = ofm->temp_rule;
    const struct rule_actions *actions = rule_get_actions(new_rule);
    struct oftable *table = &ofproto->tables[new_rule->table_id];
    enum ofperr error;

    /* Must check actions while holding ofproto_mutex to avoid a race. */
    error = ofproto_check_ofpacts(ofproto, actions->ofpacts,
                                  actions->ofpacts_len);
    if (error) {
        return error;
    }

    /* Check for the existence of an identical rule.
     * This will not return rules earlier marked for removal. */
    old_rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls,
                                                               &new_rule->cr,
                                                               ofm->version));
    if (!old_rule) {
        /* Check for overlap, if requested. */
        if (new_rule->flags & OFPUTIL_FF_CHECK_OVERLAP
            && classifier_rule_overlaps(&table->cls, &new_rule->cr,
                                        ofm->version)) {
            return OFPERR_OFPFMFC_OVERLAP;
        }

        /* If necessary, evict an existing rule to clear out space. */
        if (table->n_flows >= table->max_flows) {
            if (!choose_rule_to_evict(table, &old_rule)) {
                return OFPERR_OFPFMFC_TABLE_FULL;
            }
            eviction_group_remove_rule(old_rule);
            /* Marks 'old_rule' as an evicted rule rather than replaced rule.
             */
            old_rule->removed_reason = OFPRR_EVICTION;
        }
    } else {
        ofm->modify_cookie = true;
    }

    if (old_rule) {
        rule_collection_add(&ofm->old_rules, old_rule);
    }
    /* Take ownership of the temp_rule. */
    rule_collection_add(&ofm->new_rules, new_rule);
    ofm->temp_rule = NULL;

    replace_rule_start(ofproto, ofm, old_rule, new_rule);
    return 0;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *old_rule = rule_collection_n(&ofm->old_rules)
        ? rule_collection_rules(&ofm->old_rules)[0] : NULL;
    struct rule *new_rule = rule_collection_rules(&ofm->new_rules)[0];

    replace_rule_revert(ofproto, old_rule, new_rule);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *rule = ofm->temp_rule;

    /* ofproto_flow_mod_start() consumes the reference, so we
     * take a new one. */
    ofproto_rule_ref(rule);
    enum ofperr error = ofproto_flow_mod_start(rule->ofproto, ofm);
    ofm->temp_rule = rule;

    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *rule = rule_collection_rules(&ofm->new_rules)[0];

    /* If learning on a different bridge, must bump its version
     * number and flush connmgr afterwards. */
    if (rule->ofproto != orig_ofproto) {
        ofproto_bump_tables_version(rule->ofproto);
    }
    ofproto_flow_mod_finish(rule->ofproto, ofm, NULL);
    if (rule->ofproto != orig_ofproto) {
        ofmonitor_flush(rule->ofproto->connmgr);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *replaced_rule;

    replaced_rule = (old_rule && old_rule->removed_reason != OFPRR_EVICTION)
        ? old_rule : NULL;

    /* Insert the new flow to the ofproto provider.  A non-NULL 'replaced_rule'
     * is a duplicate rule the 'new_rule' is replacing.  The provider should
     * link the packet and byte counts from the old rule to the new one if
     * 'modify_keep_counts' is 'true'.  The 'replaced_rule' will be deleted
     * right after this call. */
    ofproto->ofproto_class->rule_insert(new_rule, replaced_rule,
                                        ofm->modify_keep_counts);
    learned_cookies_inc(ofproto, rule_get_actions(new_rule));

    if (old_rule) {
        const struct rule_actions *old_actions = rule_get_actions(old_rule);
        const struct rule_actions *new_actions = rule_get_actions(new_rule);

        learned_cookies_dec(ofproto, old_actions, dead_cookies);

        if (replaced_rule) {
            enum nx_flow_update_event event = ofm->command == OFPFC_ADD
                ? NXFME_ADDED : NXFME_MODIFIED;

            bool changed_cookie = (new_rule->flow_cookie
                                   != old_rule->flow_cookie);

            bool changed_actions = !ofpacts_equal(new_actions->ofpacts,
                                                  new_actions->ofpacts_len,
                                                  old_actions->ofpacts,
                                                  old_actions->ofpacts_len);

            if (event != NXFME_MODIFIED || changed_actions
                || changed_cookie) {
                ofmonitor_report(ofproto->connmgr, new_rule, event, 0,
                                 req ? req->ofconn : NULL,
                                 req ? req->request->xid : 0,
                                 changed_actions ? old_actions : NULL);
            }
        } else {
            /* XXX: This is slight duplication with delete_flows_finish__() */
            ofmonitor_report(ofproto->connmgr, old_rule, NXFME_DELETED,
                             OFPRR_EVICTION,
                             req ? req->ofconn : NULL,
                             req ? req->request->xid : 0, NULL);
        }
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule_collection *old_rules = &ofm->old_rules;
    struct rule_collection *new_rules = &ofm->new_rules;
    enum ofperr error;

    if (rule_collection_n(old_rules) > 0) {
        /* Create a new 'modified' rule for each old rule. */
        struct rule *old_rule, *new_rule;
        const struct rule_actions *actions = rule_get_actions(ofm->temp_rule);

        /* Must check actions while holding ofproto_mutex to avoid a race. */
        error = ofproto_check_ofpacts(ofproto, actions->ofpacts,
                                      actions->ofpacts_len);
        if (error) {
            return error;
        }

        /* Use the temp rule as the first new rule, and as the template for
         * the rest. */
        struct rule *temp = ofm->temp_rule;
        ofm->temp_rule = NULL;   /* We consume the template. */

        bool first = true;
        RULE_COLLECTION_FOR_EACH (old_rule, old_rules) {
            if (first) {
                /* The template rule's match is possibly a loose one, so it
                 * must be replaced with the old rule's match so that the new
                 * rule actually replaces the old one. */
                cls_rule_destroy(CONST_CAST(struct cls_rule *, &temp->cr));
                cls_rule_clone(CONST_CAST(struct cls_rule *, &temp->cr),
                               &old_rule->cr);
                if (temp->match_tlv_bitmap != old_rule->match_tlv_bitmap) {
                    mf_vl_mff_unref(&temp->ofproto->vl_mff_map,
                                    temp->match_tlv_bitmap);
                    temp->match_tlv_bitmap = old_rule->match_tlv_bitmap;
                    mf_vl_mff_ref(&temp->ofproto->vl_mff_map,
                                  temp->match_tlv_bitmap);
                }
                *CONST_CAST(uint8_t *, &temp->table_id) = old_rule->table_id;
                rule_collection_add(new_rules, temp);
                first = false;
            } else {
                struct cls_rule cr;
                cls_rule_clone(&cr, &old_rule->cr);
                error = ofproto_rule_create(ofproto, &cr, old_rule->table_id,
                                            temp->flow_cookie,
                                            temp->idle_timeout,
                                            temp->hard_timeout, temp->flags,
                                            temp->importance,
                                            temp->actions->ofpacts,
                                            temp->actions->ofpacts_len,
                                            old_rule->match_tlv_bitmap,
                                            temp->ofpacts_tlv_bitmap,
                                            &new_rule);
                if (!error) {
                    rule_collection_add(new_rules, new_rule);
                } else {
                    /* Return the template rule in place in the error case. */
                    ofm->temp_rule = temp;
                    rule_collection_rules(new_rules)[0] = NULL;

                    rule_collection_unref(new_rules);
                    rule_collection_destroy(new_rules);
                    return error;
                }
            }
        }
        ovs_assert(rule_collection_n(new_rules)
                   == rule_collection_n(old_rules));

        RULE_COLLECTIONS_FOR_EACH (old_rule, new_rule, old_rules, new_rules) {
            replace_rule_start(ofproto, ofm, old_rule, new_rule);
        }
    } else if (ofm->modify_may_add_flow) {
        /* No match, add a new flow, consumes 'temp'. */
        error = add_flow_start(ofproto, ofm);
    } else {
        /* No flow to modify and may not add a flow. */
        ofproto_rule_unref(ofm->temp_rule);
        ofm->temp_rule = NULL;   /* We consume the template. */
        error = 0;
    }

    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule_collection *old_rules = &ofm->old_rules;
    enum ofperr error;

    error = collect_rules_loose(ofproto, &ofm->criteria, old_rules);

    if (!error) {
        error = modify_flows_start__(ofproto, ofm);
    }

    if (error) {
        rule_collection_destroy(old_rules);
    }

    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule_collection *old_rules = &ofm->old_rules;
    struct rule_collection *new_rules = &ofm->new_rules;

    /* Old rules were not changed yet, only need to revert new rules. */
    if (rule_collection_n(old_rules) > 0) {
        struct rule *old_rule, *new_rule;
        RULE_COLLECTIONS_FOR_EACH (old_rule, new_rule, old_rules, new_rules) {
            replace_rule_revert(ofproto, old_rule, new_rule);
        }
        rule_collection_destroy(new_rules);
        rule_collection_destroy(old_rules);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule_collection *old_rules = &ofm->old_rules;
    struct rule_collection *new_rules = &ofm->new_rules;

    if (rule_collection_n(old_rules) == 0
        && rule_collection_n(new_rules) == 1) {
        add_flow_finish(ofproto, ofm, req);
    } else if (rule_collection_n(old_rules) > 0) {
        struct ovs_list dead_cookies = OVS_LIST_INITIALIZER(&dead_cookies);

        ovs_assert(rule_collection_n(new_rules)
                   == rule_collection_n(old_rules));

        struct rule *old_rule, *new_rule;
        RULE_COLLECTIONS_FOR_EACH (old_rule, new_rule, old_rules, new_rules) {
            replace_rule_finish(ofproto, ofm, req, old_rule, new_rule,
                                &dead_cookies);
        }
        learned_cookies_flush(ofproto, &dead_cookies);
        remove_rules_postponed(old_rules);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule_collection *old_rules = &ofm->old_rules;
    enum ofperr error;

    error = collect_rules_strict(ofproto, &ofm->criteria, old_rules);

    if (!error) {
        /* collect_rules_strict() can return max 1 rule. */
        error = modify_flows_start__(ofproto, ofm);
    }

    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *rule;

    RULE_COLLECTION_FOR_EACH (rule, rules) {
        struct oftable *table = &ofproto->tables[rule->table_id];

        table->n_flows--;
        cls_rule_make_invisible_in_version(&rule->cr, version);

        /* Remove rule from ofproto data structures. */
        ofproto_rule_remove__(ofproto, rule);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *rule;

    RULE_COLLECTION_FOR_EACH (rule, rules) {
        struct oftable *table = &ofproto->tables[rule->table_id];

        /* Add rule back to ofproto data structures. */
        ofproto_rule_insert__(ofproto, rule);

        /* Restore table's rule count. */
        table->n_flows++;

        /* Restore the original visibility of the rule. */
        cls_rule_restore_visibility(&rule->cr);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    if (rule_collection_n(rules)) {
        struct ofproto *ofproto = rule_collection_rules(rules)[0]->ofproto;

        delete_flows_start__(ofproto, ofproto->tables_version + 1, rules);
        ofproto_bump_tables_version(ofproto);
        delete_flows_finish__(ofproto, rules, reason, req);
        ofmonitor_flush(ofproto->connmgr);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule_collection *rules = &ofm->old_rules;
    enum ofperr error;

    error = collect_rules_loose(ofproto, &ofm->criteria, rules);

    if (!error) {
        delete_flows_start__(ofproto, ofm->version, rules);
    }

    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    delete_flows_revert__(ofproto, &ofm->old_rules);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    delete_flows_finish__(ofproto, &ofm->old_rules, OFPRR_DELETE, req);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule_collection *rules = &ofm->old_rules;
    enum ofperr error;

    error = collect_rules_strict(ofproto, &ofm->criteria, rules);

    if (!error) {
        delete_flows_start__(ofproto, ofm->version, rules);
    }

    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule_collection rules;

    rule_collection_init(&rules);
    rule_collection_add(&rules, rule);
    delete_flows__(&rules, reason, NULL);
}

Project: ovs

    OVS_REQUIRES(ofproto_mutex)
    OVS_EXCLUDED(rule->mutex)
{
    if (!idle_timeout && !hard_timeout) {
        return;
    }

    if (ovs_list_is_empty(&rule->expirable)) {
        ovs_list_insert(&rule->ofproto->expirable, &rule->expirable);
    }

    ovs_mutex_lock(&rule->mutex);
    reduce_timeout(idle_timeout, &rule->idle_timeout);
    reduce_timeout(hard_timeout, &rule->hard_timeout);
    ovs_mutex_unlock(&rule->mutex);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    const struct rule_actions *actions;
    struct ofputil_flow_update fu;

    fu.event = (flags & (NXFMF_INITIAL | NXFMF_ADD)
                ? NXFME_ADDED : NXFME_MODIFIED);
    fu.reason = 0;
    ovs_mutex_lock(&rule->mutex);
    fu.idle_timeout = rule->idle_timeout;
    fu.hard_timeout = rule->hard_timeout;
    ovs_mutex_unlock(&rule->mutex);
    fu.table_id = rule->table_id;
    fu.cookie = rule->flow_cookie;
    minimatch_expand(&rule->cr.match, &fu.match);
    fu.priority = rule->cr.priority;

    actions = flags & NXFMF_ACTIONS ? rule_get_actions(rule) : NULL;
    fu.ofpacts = actions ? actions->ofpacts : NULL;
    fu.ofpacts_len = actions ? actions->ofpacts_len : 0;

    if (ovs_list_is_empty(msgs)) {
        ofputil_start_flow_update(msgs);
    }
    ofputil_append_flow_update(&fu, msgs, tun_table);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    enum nx_flow_monitor_flags update;

    if (rule_is_hidden(rule)) {
        return;
    }

    if (!ofproto_rule_has_out_port(rule, m->out_port)) {
        return;
    }

    if (seqno) {
        if (rule->add_seqno > seqno) {
            update = NXFMF_ADD | NXFMF_MODIFY;
        } else if (rule->modify_seqno > seqno) {
            update = NXFMF_MODIFY;
        } else {
            return;
        }

        if (!(m->flags & update)) {
            return;
        }
    } else {
        update = NXFMF_INITIAL;
    }

    if (!rule->monitor_flags) {
        rule_collection_add(rules, rule);
    }
    rule->monitor_flags |= update | (m->flags & NXFMF_ACTIONS);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    const struct ofproto *ofproto = ofconn_get_ofproto(m->ofconn);
    const struct oftable *table;
    struct cls_rule target;

    cls_rule_init_from_minimatch(&target, &m->match, 0);
    FOR_EACH_MATCHING_TABLE (table, m->table_id, ofproto) {
        struct rule *rule;

        CLS_FOR_EACH_TARGET (rule, cr, &table->cls, &target, OVS_VERSION_MAX) {
            ofproto_collect_ofmonitor_refresh_rule(m, rule, seqno, rules);
        }
    }
    cls_rule_destroy(&target);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct ofmonitor *m;
    enum ofperr error;

    m = ofmonitor_lookup(ofconn, id);
    if (m) {
        ofmonitor_destroy(m);
        error = 0;
    } else {
        error = OFPERR_OFPMOFC_UNKNOWN_MONITOR;
    }

    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    for (uint32_t mid = first; mid <= last; ++mid) {
        struct meter *meter = ofproto->meters[mid];
        if (meter) {
            /* First delete the rules that use this meter. */
            if (!ovs_list_is_empty(&meter->rules)) {
                struct rule_collection rules;
                struct rule *rule;

                rule_collection_init(&rules);

                LIST_FOR_EACH (rule, meter_list_node, &meter->rules) {
                    rule_collection_add(&rules, rule);
                }
                delete_flows__(&rules, OFPRR_METER_DELETE, NULL);
            }

            ofproto->meters[mid] = NULL;
            ofproto->ofproto_class->meter_del(ofproto,
                                              meter->provider_meter_id);
            free(meter->bands);
            free(meter);
        }
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct ofputil_group_stats ogs;
    const struct ofproto *ofproto = group->ofproto;
    long long int now = time_msec();
    int error;

    ogs.bucket_stats = xmalloc(group->n_buckets * sizeof *ogs.bucket_stats);

    /* Provider sets the packet and byte counts, we do the rest. */
    ogs.ref_count = rule_collection_n(&group->rules);
    ogs.n_buckets = group->n_buckets;

    error = (ofproto->ofproto_class->group_get_stats
             ? ofproto->ofproto_class->group_get_stats(group, &ogs)
             : EOPNOTSUPP);
    if (error) {
        ogs.packet_count = UINT64_MAX;
        ogs.byte_count = UINT64_MAX;
        memset(ogs.bucket_stats, 0xff,
               ogs.n_buckets * sizeof *ogs.bucket_stats);
    }

    ogs.group_id = group->group_id;
    calc_duration(group->created, now, &ogs.duration_sec, &ogs.duration_nsec);

    ofputil_append_group_stats(replies, &ogs);

    free(ogs.bucket_stats);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    enum ofperr error;

    if (ofproto_group_exists(ofproto, ogm->gm.group_id)) {
        return OFPERR_OFPGMFC_GROUP_EXISTS;
    }

    if (ofproto->n_groups[ogm->gm.type]
        >= ofproto->ogf.max_groups[ogm->gm.type]) {
        return OFPERR_OFPGMFC_OUT_OF_GROUPS;
    }

    /* Allocate new group and initialize it. */
    error = init_group(ofproto, &ogm->gm, ogm->version, &ogm->new_group);
    if (!error) {
        /* Insert new group. */
        cmap_insert(&ofproto->groups, &ogm->new_group->cmap_node,
                    hash_int(ogm->new_group->group_id, 0));
        ofproto->n_groups[ogm->new_group->type]++;
    }
    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct ofgroup *old_group;          /* Modified group. */
    struct ofgroup *new_group;
    enum ofperr error;

    old_group = ofproto_group_lookup__(ofproto, ogm->gm.group_id,
                                       OVS_VERSION_MAX);
    if (!old_group) {
        return OFPERR_OFPGMFC_UNKNOWN_GROUP;
    }

    /* Inserting or deleting a bucket should not change the group's type or
     * properties, so change the group mod so that these aspects match the old
     * group.  (See EXT-570.)  */
    if (ogm->gm.command == OFPGC15_INSERT_BUCKET ||
        ogm->gm.command == OFPGC15_REMOVE_BUCKET) {
        ogm->gm.type = old_group->type;
        ofputil_group_properties_destroy(&ogm->gm.props);
        ofputil_group_properties_copy(&ogm->gm.props, &old_group->props);
    }

    if (old_group->type != ogm->gm.type
        && (ofproto->n_groups[ogm->gm.type]
            >= ofproto->ogf.max_groups[ogm->gm.type])) {
        return OFPERR_OFPGMFC_OUT_OF_GROUPS;
    }

    error = init_group(ofproto, &ogm->gm, ogm->version, &ogm->new_group);
    if (error) {
        return error;
    }
    new_group = ogm->new_group;

    /* Manipulate bucket list for bucket commands */
    if (ogm->gm.command == OFPGC15_INSERT_BUCKET) {
        error = copy_buckets_for_insert_bucket(old_group, new_group,
                                               ogm->gm.command_bucket_id);
    } else if (ogm->gm.command == OFPGC15_REMOVE_BUCKET) {
        error = copy_buckets_for_remove_bucket(old_group, new_group,
                                               ogm->gm.command_bucket_id);
    }
    if (error) {
        goto out;
    }

    /* The group creation time does not change during modification. */
    *CONST_CAST(long long int *, &(new_group->created)) = old_group->created;
    *CONST_CAST(long long int *, &(new_group->modified)) = time_msec();

    group_collection_add(&ogm->old_groups, old_group);

    /* Mark the old group for deletion. */
    versions_set_remove_version(&old_group->versions, ogm->version);
    /* Insert replacement group. */
    cmap_insert(&ofproto->groups, &new_group->cmap_node,
                    hash_int(new_group->group_id, 0));
    /* Transfer rules. */
    rule_collection_move(&new_group->rules, &old_group->rules);

    if (old_group->type != new_group->type) {
        ofproto->n_groups[old_group->type]--;
        ofproto->n_groups[new_group->type]++;
    }
    return 0;

out:
    ofproto_group_unref(new_group);
    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    enum ofperr error;

    if (!ofproto_group_exists(ofproto, ogm->gm.group_id)) {
        error = add_group_start(ofproto, ogm);
    } else {
        error = modify_group_start(ofproto, ogm);
    }

    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    /* Makes flow deletion code leave the rule pointers in 'group->rules'
     * intact, so that we can later refer to the rules deleted due to the group
     * deletion.  Rule pointers will be removed from all other groups, if any,
     * so we will never try to delete the same rule twice. */
    group->being_deleted = true;

    /* Mark all the referring groups for deletion. */
    delete_flows_start__(ofproto, version, &group->rules);
    group_collection_add(groups, group);
    versions_set_remove_version(&group->versions, version);
    ofproto->n_groups[group->type]--;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    /* Finish deletion of all flow entries containing this group in a group
     * action. */
    delete_flows_finish__(ofproto, &group->rules, OFPRR_GROUP_DELETE, NULL);

    /* Group removal is postponed by the caller. */
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct ofgroup *group;

    if (ogm->gm.group_id == OFPG_ALL) {
        CMAP_FOR_EACH (group, cmap_node, &ofproto->groups) {
            if (versions_visible_in_version(&group->versions, ogm->version)) {
                delete_group_start(ofproto, ogm->version, &ogm->old_groups,
                                   group);
            }
        }
    } else {
        group = ofproto_group_lookup__(ofproto, ogm->gm.group_id, ogm->version);
        if (group) {
            delete_group_start(ofproto, ogm->version, &ogm->old_groups, group);
        }
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    enum ofperr error;

    ogm->new_group = NULL;
    group_collection_init(&ogm->old_groups);

    switch (ogm->gm.command) {
    case OFPGC11_ADD:
        error = add_group_start(ofproto, ogm);
        break;

    case OFPGC11_MODIFY:
        error = modify_group_start(ofproto, ogm);
        break;

    case OFPGC11_ADD_OR_MOD:
        error = add_or_modify_group_start(ofproto, ogm);
        break;

    case OFPGC11_DELETE:
        delete_groups_start(ofproto, ogm);
        error = 0;
        break;

    case OFPGC15_INSERT_BUCKET:
        error = modify_group_start(ofproto, ogm);
        break;

    case OFPGC15_REMOVE_BUCKET:
        error = modify_group_start(ofproto, ogm);
        break;

    default:
        if (ogm->gm.command > OFPGC11_DELETE) {
            VLOG_INFO_RL(&rl, "%s: Invalid group_mod command type %d",
                         ofproto->name, ogm->gm.command);
        }
        error = OFPERR_OFPGMFC_BAD_COMMAND;
        break;
    }
    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct ofgroup *new_group = ogm->new_group;
    struct ofgroup *old_group;

    /* Restore replaced or deleted groups. */
    GROUP_COLLECTION_FOR_EACH (old_group, &ogm->old_groups) {
        ofproto->n_groups[old_group->type]++;
        if (new_group) {
            ovs_assert(group_collection_n(&ogm->old_groups) == 1);
            /* Transfer rules back. */
            rule_collection_move(&old_group->rules, &new_group->rules);
        } else {
            old_group->being_deleted = false;
            /* Revert rule deletion. */
            delete_flows_revert__(ofproto, &old_group->rules);
        }
        /* Restore visibility. */
        versions_set_remove_version(&old_group->versions,
                                    OVS_VERSION_NOT_REMOVED);
    }
    if (new_group) {
        /* Remove the new group immediately.  It was never visible to
         * lookups. */
        cmap_remove(&ofproto->groups, &new_group->cmap_node,
                    hash_int(new_group->group_id, 0));
        ofproto->n_groups[new_group->type]--;
        ofproto_group_unref(new_group);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct ofgroup *new_group = ogm->new_group;
    struct ofgroup *old_group;

    if (new_group && group_collection_n(&ogm->old_groups) &&
        ofproto->ofproto_class->group_modify) {
        /* Modify a group. */
        ovs_assert(group_collection_n(&ogm->old_groups) == 1);

        /* XXX: OK to lose old group's stats? */
        ofproto->ofproto_class->group_modify(new_group);
    }

    /* Delete old groups. */
    GROUP_COLLECTION_FOR_EACH(old_group, &ogm->old_groups) {
        delete_group_finish(ofproto, old_group);
    }
    remove_groups_postponed(&ogm->old_groups);

    if (req) {
        struct ofputil_requestforward rf;
        rf.xid = req->request->xid;
        rf.reason = OFPRFR_GROUP_MOD;
        rf.group_mod = &ogm->gm;
        connmgr_send_requestforward(ofproto->connmgr, req->ofconn, &rf);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    enum ofperr error;

    rule_collection_init(&ofm->old_rules);
    rule_collection_init(&ofm->new_rules);

    switch (ofm->command) {
    case OFPFC_ADD:
        error = add_flow_start(ofproto, ofm);
        break;
    case OFPFC_MODIFY:
        error = modify_flows_start_loose(ofproto, ofm);
        break;
    case OFPFC_MODIFY_STRICT:
        error = modify_flow_start_strict(ofproto, ofm);
        break;
    case OFPFC_DELETE:
        error = delete_flows_start_loose(ofproto, ofm);
        break;
    case OFPFC_DELETE_STRICT:
        error = delete_flow_start_strict(ofproto, ofm);
        break;
    default:
        OVS_NOT_REACHED();
    }
    /* Release resources not needed after start. */
    ofproto_flow_mod_uninit(ofm);

    if (error) {
        rule_collection_destroy(&ofm->old_rules);
        rule_collection_destroy(&ofm->new_rules);
    }
    return error;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    switch (ofm->command) {
    case OFPFC_ADD:
        add_flow_revert(ofproto, ofm);
        break;

    case OFPFC_MODIFY:
    case OFPFC_MODIFY_STRICT:
        modify_flows_revert(ofproto, ofm);
        break;

    case OFPFC_DELETE:
    case OFPFC_DELETE_STRICT:
        delete_flows_revert(ofproto, ofm);
        break;

    default:
        break;
    }

    rule_collection_destroy(&ofm->old_rules);
    rule_collection_destroy(&ofm->new_rules);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    switch (ofm->command) {
    case OFPFC_ADD:
        add_flow_finish(ofproto, ofm, req);
        break;

    case OFPFC_MODIFY:
    case OFPFC_MODIFY_STRICT:
        modify_flows_finish(ofproto, ofm, req);
        break;

    case OFPFC_DELETE:
    case OFPFC_DELETE_STRICT:
        delete_flows_finish(ofproto, ofm, req);
        break;

    default:
        break;
    }

    rule_collection_destroy(&ofm->old_rules);
    rule_collection_destroy(&ofm->new_rules);

    if (req) {
        ofconn_report_flow_mod(req->ofconn, ofm->command);
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct eviction_group *evg;

    *rulep = NULL;
    if (!table->eviction) {
        return false;
    }

    /* In the common case, the outer and inner loops here will each be entered
     * exactly once:
     *
     *   - The inner loop normally "return"s in its first iteration.  If the
     *     eviction group has any evictable rules, then it always returns in
     *     some iteration.
     *
     *   - The outer loop only iterates more than once if the largest eviction
     *     group has no evictable rules.
     *
     *   - The outer loop can exit only if table's 'max_flows' is all filled up
     *     by unevictable rules. */
    HEAP_FOR_EACH (evg, size_node, &table->eviction_groups_by_size) {
        struct rule *rule;

        HEAP_FOR_EACH (rule, evg_node, &evg->rules) {
            *rulep = rule;
            return true;
        }
    }

    return false;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    heap_change(&table->eviction_groups_by_size, &evg->size_node,
                eviction_group_priority(heap_count(&evg->rules)));
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    while (!heap_is_empty(&evg->rules)) {
        struct rule *rule;

        rule = CONTAINER_OF(heap_pop(&evg->rules), struct rule, evg_node);
        rule->eviction_group = NULL;
    }
    hmap_remove(&table->eviction_groups_by_id, &evg->id_node);
    heap_remove(&table->eviction_groups_by_size, &evg->size_node);
    heap_destroy(&evg->rules);
    free(evg);
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    if (rule->eviction_group) {
        struct oftable *table = &rule->ofproto->tables[rule->table_id];
        struct eviction_group *evg = rule->eviction_group;

        rule->eviction_group = NULL;
        heap_remove(&evg->rules, &rule->evg_node);
        if (heap_is_empty(&evg->rules)) {
            eviction_group_destroy(table, evg);
        } else {
            eviction_group_resized(table, evg);
        }
    }
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct eviction_group *evg;

    HMAP_FOR_EACH_WITH_HASH (evg, id_node, id, &table->eviction_groups_by_id) {
        return evg;
    }

    evg = xmalloc(sizeof *evg);
    hmap_insert(&table->eviction_groups_by_id, &evg->id_node, id);
    heap_insert(&table->eviction_groups_by_size, &evg->size_node,
                eviction_group_priority(0));
    heap_init(&evg->rules);

    return evg;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    /* Calculate absolute time when this flow will expire.  If it will never
     * expire, then return 0 to make it unevictable.  */
    long long int expiration = LLONG_MAX;
    if (rule->hard_timeout) {
        /* 'modified' needs protection even when we hold 'ofproto_mutex'. */
        ovs_mutex_lock(&rule->mutex);
        long long int modified = rule->modified;
        ovs_mutex_unlock(&rule->mutex);

        expiration = modified + rule->hard_timeout * 1000;
    }
    if (rule->idle_timeout) {
        uint64_t packets, bytes;
        long long int used;
        long long int idle_expiration;

        ofproto->ofproto_class->rule_get_stats(rule, &packets, &bytes, &used);
        idle_expiration = used + rule->idle_timeout * 1000;
        expiration = MIN(expiration, idle_expiration);
    }
    if (expiration == LLONG_MAX) {
        return 0;
    }

    /* Calculate the time of expiration as a number of (approximate) seconds
     * after program startup.
     *
     * This should work OK for program runs that last UINT32_MAX seconds or
     * less.  Therefore, please restart OVS at least once every 136 years. */
    uint32_t expiration_ofs = (expiration >> 10) - (time_boot_msec() >> 10);

    /* Combine expiration time with OpenFlow "importance" to form a single
     * priority value.  We want flows with relatively low "importance" to be
     * evicted before even considering expiration time, so put "importance" in
     * the most significant bits and expiration time in the least significant
     * bits.
     *
     * Small 'priority' should be evicted before those with large 'priority'.
     * The caller expects the opposite convention (a large return value being
     * more attractive for eviction) so we invert it before returning. */
    uint64_t priority = ((uint64_t) rule->importance << 32) + expiration_ofs;
    return UINT64_MAX - priority;
}

Project: ovs
File: ofproto.c

    OVS_REQUIRES(ofproto_mutex)
{
    struct rule *rule;

    if ((table->eviction != 0) == (eviction != 0)
        && n_fields == table->n_eviction_fields
        && (!n_fields
            || !memcmp(fields, table->eviction_fields,
                       n_fields * sizeof *fields))) {
        /* The set of eviction fields did not change.  If 'eviction' changed,
         * it remains nonzero, so that we can just update table->eviction
         * without fussing with the eviction groups. */
        table->eviction = eviction;
        return;
    }

    /* Destroy existing eviction groups, then destroy and recreate data
     * structures to recover memory. */
    struct eviction_group *evg, *next;
    HMAP_FOR_EACH_SAFE (evg, next, id_node, &table->eviction_groups_by_id) {
        eviction_group_destroy(table, evg);
    }
    hmap_destroy(&table->eviction_groups_by_id);
    hmap_init(&table->eviction_groups_by_id);
    heap_destroy(&table->eviction_groups_by_size);
    heap_init(&table->eviction_groups_by_size);

    /* Replace eviction groups by the new ones, if there is a change.  Free the
     * old fields only after allocating the new ones, because 'fields ==
     * table->eviction_fields' is possible. */
    struct mf_subfield *old_fields = table->eviction_fields;
    table->n_eviction_fields = n_fields;
    table->eviction_fields = (fields
                              ? xmemdup(fields, n_fields * sizeof *fields)
                              : NULL);
    free(old_fields);

    /* Add the new eviction groups, if enabled. */
    table->eviction = eviction;
    if (table->eviction) {
        table->eviction_group_id_basis = random_uint32();
        CLS_FOR_EACH (rule, cr, &table->cls) {
            eviction_group_add_rule(rule);
        }
    }
}

Project: ovs
File: ofproto.c

age_secs(long long int age_ms)
{
    return (age_ms < 0 ? 0
            : age_ms >= UINT16_MAX * 1000 ? UINT16_MAX
            : (unsigned int) age_ms / 1000);
}

Project: ovs
File: ofproto.c

alloc_ofp_port(struct ofproto *ofproto, const char *netdev_name)
{
    uint16_t port_idx;

    port_idx = simap_get(&ofproto->ofp_requests, netdev_name);
    port_idx = port_idx ? port_idx : UINT16_MAX;

    if (port_idx >= ofproto->max_ports
        || ofport_get_usage(ofproto, u16_to_ofp(port_idx)) == LLONG_MAX) {
        uint16_t lru_ofport = 0, end_port_no = ofproto->alloc_port_no;
        long long int last_used_at, lru = LLONG_MAX;

        /* Search for a free OpenFlow port number.  We try not to
         * immediately reuse them to prevent problems due to old
         * flows.
         *
         * We limit the automatically assigned port numbers to the lower half
         * of the port range, to reserve the upper half for assignment by
         * controllers. */
        for (;;) {
            if (++ofproto->alloc_port_no >= MIN(ofproto->max_ports, 32768)) {
                ofproto->alloc_port_no = 1;
            }
            last_used_at = ofport_get_usage(ofproto,
                                         u16_to_ofp(ofproto->alloc_port_no));
            if (!last_used_at) {
                port_idx = ofproto->alloc_port_no;
                break;
            } else if ( last_used_at < time_msec() - 60*60*1000) {
                /* If the port with ofport 'ofproto->alloc_port_no' was deleted
                 * more than an hour ago, consider it usable. */
                ofport_remove_usage(ofproto,
                    u16_to_ofp(ofproto->alloc_port_no));
                port_idx = ofproto->alloc_port_no;
                break;
            } else if (last_used_at < lru) {
                lru = last_used_at;
                lru_ofport = ofproto->alloc_port_no;
            }

            if (ofproto->alloc_port_no == end_port_no) {
                if (lru_ofport) {
                    port_idx = lru_ofport;
                    break;
                }
                return OFPP_NONE;
            }
        }
    }
    ofport_set_usage(ofproto, u16_to_ofp(port_idx), LLONG_MAX);
    return u16_to_ofp(port_idx);
}

Project: ovs
File: ofproto.c

append_group_desc(struct ofgroup *group, struct ovs_list *replies)
{
    struct ofputil_group_desc gds;

    gds.group_id = group->group_id;
    gds.type = group->type;
    gds.props = group->props;

    ofputil_append_group_desc_reply(&gds, &group->buckets, replies);
}

Project: ovs
File: ofproto.c

append_port_stat(struct ofport *port, struct ovs_list *replies)
{
    struct ofputil_port_stats ops = { .port_no = port->pp.port_no };

    calc_duration(port->created, time_msec(),
                  &ops.duration_sec, &ops.duration_nsec);

    /* Intentionally ignore return value, since errors will set
     * 'stats' to all-1s, which is correct for OpenFlow, and
     * netdev_get_stats() will log errors. */
    ofproto_port_get_stats(port, &ops.stats);

    ofputil_append_port_stat(replies, &ops);
}

Project: ovs
File: ofproto.c

calc_duration(long long int start, long long int now,
              uint32_t *sec, uint32_t *nsec)
{
    long long int msecs = now - start;
    *sec = msecs / 1000;
    *nsec = (msecs % 1000) * (1000 * 1000);
}

Project: ovs
File: ofproto.c

copy_buckets_for_insert_bucket(const struct ofgroup *ofgroup,
                               struct ofgroup *new_ofgroup,
                               uint32_t command_bucket_id)
{
    struct ofputil_bucket *last = NULL;

    if (command_bucket_id <= OFPG15_BUCKET_MAX) {
        /* Check here to ensure that a bucket corresponding to
         * command_bucket_id exists in the old bucket list.
         *
         * The subsequent search of below of new_ofgroup covers
         * both buckets in the old bucket list and buckets added
         * by the insert buckets group mod message this function processes. */
        if (!ofputil_bucket_find(&ofgroup->buckets, command_bucket_id)) {
            return OFPERR_OFPGMFC_UNKNOWN_BUCKET;
        }

        if (!ovs_list_is_empty(&new_ofgroup->buckets)) {
            last = ofputil_bucket_list_back(&new_ofgroup->buckets);
        }
    }

    ofputil_bucket_clone_list(CONST_CAST(struct ovs_list *,
                                         &new_ofgroup->buckets),
                              &ofgroup->buckets, NULL);

    if (ofputil_bucket_check_duplicate_id(&new_ofgroup->buckets)) {
            VLOG_INFO_RL(&rl, "Duplicate bucket id");
            return OFPERR_OFPGMFC_BUCKET_EXISTS;
    }

    /* Rearrange list according to command_bucket_id */
    if (command_bucket_id == OFPG15_BUCKET_LAST) {
        if (!ovs_list_is_empty(&ofgroup->buckets)) {
            struct ofputil_bucket *new_first;
            const struct ofputil_bucket *first;

            first = ofputil_bucket_list_front(&ofgroup->buckets);
            new_first = ofputil_bucket_find(&new_ofgroup->buckets,
                                            first->bucket_id);

            ovs_list_splice(new_ofgroup->buckets.next, &new_first->list_node,
                            CONST_CAST(struct ovs_list *,
                                       &new_ofgroup->buckets));
        }
    } else if (command_bucket_id <= OFPG15_BUCKET_MAX && last) {
        struct ofputil_bucket *after;

        /* Presence of bucket is checked above so after should never be NULL */
        after = ofputil_bucket_find(&new_ofgroup->buckets, command_bucket_id);

        ovs_list_splice(after->list_node.next, new_ofgroup->buckets.next,
                    last->list_node.next);
    }

    return 0;
}

Project: ovs
File: ofproto.c

copy_buckets_for_remove_bucket(const struct ofgroup *ofgroup,
                               struct ofgroup *new_ofgroup,
                               uint32_t command_bucket_id)
{
    const struct ofputil_bucket *skip = NULL;

    if (command_bucket_id == OFPG15_BUCKET_ALL) {
        return 0;
    }

    if (command_bucket_id == OFPG15_BUCKET_FIRST) {
        if (!ovs_list_is_empty(&ofgroup->buckets)) {
            skip = ofputil_bucket_list_front(&ofgroup->buckets);
        }
    } else if (command_bucket_id == OFPG15_BUCKET_LAST) {
        if (!ovs_list_is_empty(&ofgroup->buckets)) {
            skip = ofputil_bucket_list_back(&ofgroup->buckets);
        }
    } else {
        skip = ofputil_bucket_find(&ofgroup->buckets, command_bucket_id);
        if (!skip) {
            return OFPERR_OFPGMFC_UNKNOWN_BUCKET;
        }
    }

    ofputil_bucket_clone_list(CONST_CAST(struct ovs_list *,
                                         &new_ofgroup->buckets),
                              &ofgroup->buckets, skip);

    return 0;
}

Project: ovs
File: ofproto.c

dealloc_ofp_port(struct ofproto *ofproto, ofp_port_t ofp_port)
{
    if (ofp_to_u16(ofp_port) < ofproto->max_ports) {
        ofport_set_usage(ofproto, ofp_port, time_msec());
    }
}

Project: ovs
File: ofproto.c

do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    ovs_version_t version = ofproto->tables_version + 1;
    struct ofp_bundle *bundle;
    struct ofp_bundle_entry *be;
    enum ofperr error;

    bundle = ofconn_get_bundle(ofconn, id);

    if (!bundle) {
        return OFPERR_OFPBFC_BAD_ID;
    }
    if (bundle->flags != flags) {
        error = OFPERR_OFPBFC_BAD_FLAGS;
    } else {
        bool prev_is_port_mod = false;

        error = 0;
        ovs_mutex_lock(&ofproto_mutex);

        /* 1. Begin. */
        LIST_FOR_EACH (be, node, &bundle->msg_list) {
            if (be->type == OFPTYPE_PORT_MOD) {
                /* Our port mods are not atomic. */
                if (flags & OFPBF_ATOMIC) {
                    error = OFPERR_OFPBFC_MSG_FAILED;
                } else {
                    prev_is_port_mod = true;
                    error = port_mod_start(ofconn, &be->opm.pm, &be->opm.port);
                }
            } else {
                /* Flow & group mods between port mods are applied as a single
                 * version, but the versions are published only after we know
                 * the commit is successful. */
                if (prev_is_port_mod) {
                    prev_is_port_mod = false;
                    ++version;
                }
                if (be->type == OFPTYPE_FLOW_MOD) {
                    /* Store the version in which the changes should take
                     * effect. */
                    be->ofm.version = version;
                    error = ofproto_flow_mod_start(ofproto, &be->ofm);
                } else if (be->type == OFPTYPE_GROUP_MOD) {
                    /* Store the version in which the changes should take
                     * effect. */
                    be->ogm.version = version;
                    error = ofproto_group_mod_start(ofproto, &be->ogm);
                } else if (be->type == OFPTYPE_PACKET_OUT) {
                    be->opo.version = version;
                    error = ofproto_packet_out_start(ofproto, &be->opo);
                } else {
                    OVS_NOT_REACHED();
                }
            }
            if (error) {
                break;
            }
        }

        if (error) {
            /* Send error referring to the original message. */
            if (error) {
                ofconn_send_error(ofconn, &be->ofp_msg, error);
                error = OFPERR_OFPBFC_MSG_FAILED;
            }

            /* 2. Revert.  Undo all the changes made above. */
            LIST_FOR_EACH_REVERSE_CONTINUE(be, node, &bundle->msg_list) {
                if (be->type == OFPTYPE_FLOW_MOD) {
                    ofproto_flow_mod_revert(ofproto, &be->ofm);
                } else if (be->type == OFPTYPE_GROUP_MOD) {
                    ofproto_group_mod_revert(ofproto, &be->ogm);
                } else if (be->type == OFPTYPE_PACKET_OUT) {
                    ofproto_packet_out_revert(ofproto, &be->opo);
                }
                /* Nothing needs to be reverted for a port mod. */
            }
        } else {
            /* 4. Finish. */
            LIST_FOR_EACH (be, node, &bundle->msg_list) {
                if (be->type == OFPTYPE_PORT_MOD) {
                    /* Perform the actual port mod. This is not atomic, i.e.,
                     * the effects will be immediately seen by upcall
                     * processing regardless of the lookup version.  It should
                     * be noted that port configuration changes can originate
                     * also from OVSDB changes asynchronously to all upcall
                     * processing. */
                    port_mod_finish(ofconn, &be->opm.pm, be->opm.port);
                } else {
                    version =
                        (be->type == OFPTYPE_FLOW_MOD) ? be->ofm.version :
                        (be->type == OFPTYPE_GROUP_MOD) ? be->ogm.version :
                        (be->type == OFPTYPE_PACKET_OUT) ? be->opo.version :
                        version;

                    /* Bump the lookup version to the one of the current
                     * message.  This makes all the changes in the bundle at
                     * this version visible to lookups at once. */
                    if (ofproto->tables_version < version) {
                        ofproto->tables_version = version;
                        ofproto->ofproto_class->set_tables_version(
                            ofproto, ofproto->tables_version);
                    }

                    struct openflow_mod_requester req = { ofconn,
                                                          &be->ofp_msg };

                    if (be->type == OFPTYPE_FLOW_MOD) {
                        ofproto_flow_mod_finish(ofproto, &be->ofm, &req);
                    } else if (be->type == OFPTYPE_GROUP_MOD) {
                        ofproto_group_mod_finish(ofproto, &be->ogm, &req);
                    } else if (be->type == OFPTYPE_PACKET_OUT) {
                        ofproto_packet_out_finish(ofproto, &be->opo);
                    }
                }
            }
        }

        ofmonitor_flush(ofproto->connmgr);
        ovs_mutex_unlock(&ofproto_mutex);
    }

    /* The bundle is discarded regardless the outcome. */
    ofp_bundle_remove__(ofconn, bundle);
    return error;
}

Project: ovs
File: ofproto.c

eviction_group_priority(size_t n_rules)
{
    uint16_t size = MIN(UINT16_MAX, n_rules);
    return (size << 16) | random_uint16();
}

Project: ovs
File: ofproto.c

find_min_mtu(struct ofproto *p)
{
    struct ofport *ofport;
    int mtu = 0;

    HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
        struct netdev *netdev = ofport->netdev;
        int dev_mtu;

        /* Skip any overridden port, since that's what we're trying to set. */
        if (ofport_is_mtu_overridden(p, ofport)) {
            continue;
        }

        if (netdev_get_mtu(netdev, &dev_mtu)) {
            continue;
        }
        if (!mtu || dev_mtu < mtu) {
            mtu = dev_mtu;
        }
    }

    return mtu ? mtu: ETH_PAYLOAD_MAX;
}

Project: ovs
File: ofproto.c

first_matching_table(const struct ofproto *ofproto, uint8_t table_id)
{
    if (table_id == 0xff) {
        return next_visible_table(ofproto, 0);
    } else if (table_id < ofproto->n_tables) {
        return &ofproto->tables[table_id];
    } else {
        return NULL;
    }
}

Project: ovs
File: ofproto.c

flow_mod_init(struct ofputil_flow_mod *fm,
              const struct match *match, int priority,
              const struct ofpact *ofpacts, size_t ofpacts_len,
              enum ofp_flow_mod_command command)
{
    *fm = (struct ofputil_flow_mod) {
        .match = *match,
        .priority = priority,
        .table_id = 0,
        .command = command,
        .buffer_id = UINT32_MAX,
        .out_port = OFPP_ANY,
        .out_group = OFPG_ANY,
        .ofpacts = CONST_CAST(struct ofpact *, ofpacts),
        .ofpacts_len = ofpacts_len,
    };
}

Project: ovs
File: ofproto.c

flow_stats_ds(struct ofproto *ofproto, struct rule *rule, struct ds *results)
{
    uint64_t packet_count, byte_count;
    const struct rule_actions *actions;
    long long int created, used;

    rule->ofproto->ofproto_class->rule_get_stats(rule, &packet_count,
                                                 &byte_count, &used);

    ovs_mutex_lock(&rule->mutex);
    actions = rule_get_actions(rule);
    created = rule->created;
    ovs_mutex_unlock(&rule->mutex);

    if (rule->table_id != 0) {
        ds_put_format(results, "table_id=%"PRIu8", ", rule->table_id);
    }
    ds_put_format(results, "duration=%llds, ", (time_msec() - created) / 1000);
    ds_put_format(results, "n_packets=%"PRIu64", ", packet_count);
    ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
    cls_rule_format(&rule->cr, ofproto_get_tun_tab(ofproto), results);
    ds_put_char(results, ',');

    ds_put_cstr(results, "actions=");
    ofpacts_format(actions->ofpacts, actions->ofpacts_len, results);

    ds_put_cstr(results, "\n");
}

Project: ovs
File: ofproto.c

get_conjunctions(const struct ofputil_flow_mod *fm,
                 struct cls_conjunction **conjsp, size_t *n_conjsp)
{
    struct cls_conjunction *conjs = NULL;
    int n_conjs = 0;

    const struct ofpact *ofpact;
    OFPACT_FOR_EACH (ofpact, fm->ofpacts, fm->ofpacts_len) {
        if (ofpact->type == OFPACT_CONJUNCTION) {
            n_conjs++;
        } else if (ofpact->type != OFPACT_NOTE) {
            /* "conjunction" may appear with "note" actions but not with any
             * other type of actions. */
            ovs_assert(!n_conjs);
            break;
        }
    }
    if (n_conjs) {
        int i = 0;

        conjs = xzalloc(n_conjs * sizeof *conjs);
        OFPACT_FOR_EACH (ofpact, fm->ofpacts, fm->ofpacts_len) {
            if (ofpact->type == OFPACT_CONJUNCTION) {
                struct ofpact_conjunction *oc = ofpact_get_CONJUNCTION(ofpact);
                conjs[i].clause = oc->clause;
                conjs[i].n_clauses = oc->n_clauses;
                conjs[i].id = oc->id;
                i++;
            }
        }
    }

    *conjsp = conjs;
    *n_conjsp = n_conjs;
}

Project: ovs
File: ofproto.c

get_provider_meter_id(const struct ofproto *ofproto, uint32_t of_meter_id)
{
    if (of_meter_id && of_meter_id <= ofproto->meter_features.max_meters) {
        const struct meter *meter = ofproto->meters[of_meter_id];
        if (meter) {
            return meter->provider_meter_id.uint32;
        }
    }
    return UINT32_MAX;
}

Project: ovs
File: ofproto.c

group_add_rule(struct ofgroup *group, struct rule *rule)
{
    rule_collection_add(&group->rules, rule);
}

Project: ovs
File: ofproto.c

group_destroy_cb(struct ofgroup *group)
{
    group->ofproto->ofproto_class->group_destruct(group);
    ofputil_group_properties_destroy(CONST_CAST(struct ofputil_group_props *,
                                                &group->props));
    ofputil_bucket_list_destroy(CONST_CAST(struct ovs_list *,
                                           &group->buckets));
    group->ofproto->ofproto_class->group_dealloc(group);
}

Project: ovs
File: ofproto.c

handle_add_meter(struct ofproto *ofproto, struct ofputil_meter_mod *mm)
{
    ofproto_meter_id provider_meter_id = { UINT32_MAX };
    struct meter **meterp = &ofproto->meters[mm->meter.meter_id];
    enum ofperr error;

    if (*meterp) {
        return OFPERR_OFPMMFC_METER_EXISTS;
    }

    error = ofproto->ofproto_class->meter_set(ofproto, &provider_meter_id,
                                              &mm->meter);
    if (!error) {
        ovs_assert(provider_meter_id.uint32 != UINT32_MAX);
        *meterp = meter_create(&mm->meter, provider_meter_id);
    }
    return error;
}

Project: ovs
File: ofproto.c

handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofpbuf *buf;

    buf = ofpraw_alloc_reply((oh->version == OFP10_VERSION
                              ? OFPRAW_OFPT10_BARRIER_REPLY
                              : OFPRAW_OFPT11_BARRIER_REPLY), oh, 0);
    ofconn_send_reply(ofconn, buf);
    return 0;
}

Project: ovs
File: ofproto.c

handle_desc_stats_request(struct ofconn *ofconn,
                          const struct ofp_header *request)
{
    static const char *default_mfr_desc = "Nicira, Inc.";
    static const char *default_hw_desc = "Open vSwitch";
    static const char *default_sw_desc = VERSION;
    static const char *default_serial_desc = "None";
    static const char *default_dp_desc = "None";

    struct ofproto *p = ofconn_get_ofproto(ofconn);
    struct ofp_desc_stats *ods;
    struct ofpbuf *msg;

    msg = ofpraw_alloc_stats_reply(request, 0);
    ods = ofpbuf_put_zeros(msg, sizeof *ods);
    ovs_strlcpy(ods->mfr_desc, p->mfr_desc ? p->mfr_desc : default_mfr_desc,
                sizeof ods->mfr_desc);
    ovs_strlcpy(ods->hw_desc, p->hw_desc ? p->hw_desc : default_hw_desc,
                sizeof ods->hw_desc);
    ovs_strlcpy(ods->sw_desc, p->sw_desc ? p->sw_desc : default_sw_desc,
                sizeof ods->sw_desc);
    ovs_strlcpy(ods->serial_num,
                p->serial_desc ? p->serial_desc : default_serial_desc,
                sizeof ods->serial_num);
    ovs_strlcpy(ods->dp_desc, p->dp_desc ? p->dp_desc : default_dp_desc,
                sizeof ods->dp_desc);
    ofconn_send_reply(ofconn, msg);

    return 0;
}

Project: ovs
File: ofproto.c

handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_switch_features features;
    struct ofport *port;
    bool arp_match_ip;
    struct ofpbuf *b;

    query_switch_features(ofproto, &arp_match_ip, &features.ofpacts);

    features.datapath_id = ofproto->datapath_id;
    features.n_buffers = 0;
    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 |
                             OFPUTIL_C_GROUP_STATS | OFPUTIL_C_BUNDLES);
    if (arp_match_ip) {
        features.capabilities |= OFPUTIL_C_ARP_MATCH_IP;
    }
    /* FIXME: Fill in proper features.auxiliary_id for auxiliary connections */
    features.auxiliary_id = 0;
    b = ofputil_encode_switch_features(&features, ofconn_get_protocol(ofconn),
                                       oh->xid);
    HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
        ofputil_put_switch_features_port(&port->pp, b);
    }

    ofconn_send_reply(ofconn, b);
    return 0;
}

Project: ovs
File: ofproto.c

handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofputil_switch_config config;
    config.frag = ofconn_get_ofproto(ofconn)->frag_handling;
    config.invalid_ttl_to_controller
        = ofconn_get_invalid_ttl_to_controller(ofconn);
    config.miss_send_len = ofconn_get_miss_send_len(ofconn);

    ofconn_send_reply(ofconn, ofputil_encode_get_config_reply(oh, &config));

    return 0;
}

Project: ovs
File: ofproto.c

handle_group_features_stats_request(struct ofconn *ofconn,
                                    const struct ofp_header *request)
{
    struct ofproto *p = ofconn_get_ofproto(ofconn);
    struct ofpbuf *msg;

    msg = ofputil_encode_group_features_reply(&p->ogf, request);
    if (msg) {
        ofconn_send_reply(ofconn, msg);
    }

    return 0;
}

Project: ovs
File: ofproto.c

handle_group_stats_request(struct ofconn *ofconn,
                           const struct ofp_header *request)
{
    uint32_t group_id;
    enum ofperr error;

    error = ofputil_decode_group_stats_request(request, &group_id);
    if (error) {
        return error;
    }

    handle_group_request(ofconn, request, group_id, append_group_stats);
    return 0;
}

Project: ovs
File: ofproto.c

handle_ipfix_bridge_stats_request(struct ofconn *ofconn,
                                  const struct ofp_header *request)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ovs_list replies;
    enum ofperr error;

    ofpmp_init(&replies, request);
    error = ofproto_get_ipfix_stats(ofproto, true, &replies);

    if (!error) {
        ofconn_send_replies(ofconn, &replies);
    } else {
        ofpbuf_list_delete(&replies);
    }

    return error;
}

Project: ovs
File: ofproto.c

handle_ipfix_flow_stats_request(struct ofconn *ofconn,
                                const struct ofp_header *request)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ovs_list replies;
    enum ofperr error;

    ofpmp_init(&replies, request);
    error = ofproto_get_ipfix_stats(ofproto, false, &replies);

    if (!error) {
        ofconn_send_replies(ofconn, &replies);
    } else {
        ofpbuf_list_delete(&replies);
    }

    return error;
}

Project: ovs
File: ofproto.c

handle_meter_features_request(struct ofconn *ofconn,
                              const struct ofp_header *request)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_meter_features features;
    struct ofpbuf *b;

    if (ofproto->ofproto_class->meter_get_features) {
        ofproto->ofproto_class->meter_get_features(ofproto, &features);
    } else {
        memset(&features, 0, sizeof features);
    }
    b = ofputil_encode_meter_features_reply(&features, request);

    ofconn_send_reply(ofconn, b);
    return 0;
}

Project: ovs
File: ofproto.c

handle_meter_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_meter_mod mm;
    uint64_t bands_stub[256 / 8];
    struct ofpbuf bands;
    uint32_t meter_id;
    enum ofperr error;

    error = reject_slave_controller(ofconn);
    if (error) {
        return error;
    }

    ofpbuf_use_stub(&bands, bands_stub, sizeof bands_stub);

    error = ofputil_decode_meter_mod(oh, &mm, &bands);
    if (error) {
        goto exit_free_bands;
    }

    meter_id = mm.meter.meter_id;

    if (mm.command != OFPMC13_DELETE) {
        /* Fails also when meters are not implemented by the provider. */
        if (meter_id == 0 || meter_id > OFPM13_MAX) {
            error = OFPERR_OFPMMFC_INVALID_METER;
            goto exit_free_bands;
        } else if (meter_id > ofproto->meter_features.max_meters) {
            error = OFPERR_OFPMMFC_OUT_OF_METERS;
            goto exit_free_bands;
        }
        if (mm.meter.n_bands > ofproto->meter_features.max_bands) {
            error = OFPERR_OFPMMFC_OUT_OF_BANDS;
            goto exit_free_bands;
        }
    }

    switch (mm.command) {
    case OFPMC13_ADD:
        error = handle_add_meter(ofproto, &mm);
        break;

    case OFPMC13_MODIFY:
        error = handle_modify_meter(ofproto, &mm);
        break;

    case OFPMC13_DELETE:
        error = handle_delete_meter(ofconn, &mm);
        break;

    default:
        error = OFPERR_OFPMMFC_BAD_COMMAND;
        break;
    }

    if (!error) {
        struct ofputil_requestforward rf;
        rf.xid = oh->xid;
        rf.reason = OFPRFR_METER_MOD;
        rf.meter_mod = &mm;
        connmgr_send_requestforward(ofproto->connmgr, ofconn, &rf);
    }

exit_free_bands:
    ofpbuf_uninit(&bands);
    return error;
}

Project: ovs
File: ofproto.c

handle_meter_request(struct ofconn *ofconn, const struct ofp_header *request,
                     enum ofptype type)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ovs_list replies;
    uint64_t bands_stub[256 / 8];
    struct ofpbuf bands;
    uint32_t meter_id, first, last;

    ofputil_decode_meter_request(request, &meter_id);

    if (meter_id == OFPM13_ALL) {
        first = 1;
        last = ofproto->meter_features.max_meters;
    } else {
        if (!meter_id || meter_id > ofproto->meter_features.max_meters ||
            !ofproto->meters[meter_id]) {
            return OFPERR_OFPMMFC_UNKNOWN_METER;
        }
        first = last = meter_id;
    }

    ofpbuf_use_stub(&bands, bands_stub, sizeof bands_stub);
    ofpmp_init(&replies, request);

    for (meter_id = first; meter_id <= last; ++meter_id) {
        struct meter *meter = ofproto->meters[meter_id];
        if (!meter) {
            continue; /* Skip non-existing meters. */
        }
        if (type == OFPTYPE_METER_STATS_REQUEST) {
            struct ofputil_meter_stats stats;

            stats.meter_id = meter_id;

            /* Provider sets the packet and byte counts, we do the rest. */
            stats.flow_count = ovs_list_size(&meter->rules);
            calc_duration(meter->created, time_msec(),
                          &stats.duration_sec, &stats.duration_nsec);
            stats.n_bands = meter->n_bands;
            ofpbuf_clear(&bands);
            stats.bands
                = ofpbuf_put_uninit(&bands,
                                    meter->n_bands * sizeof *stats.bands);

            if (!ofproto->ofproto_class->meter_get(ofproto,
                                                   meter->provider_meter_id,
                                                   &stats)) {
                ofputil_append_meter_stats(&replies, &stats);
            }
        } else { /* type == OFPTYPE_METER_CONFIG_REQUEST */
            struct ofputil_meter_config config;

            config.meter_id = meter_id;
            config.flags = meter->flags;
            config.n_bands = meter->n_bands;
            config.bands = meter->bands;
            ofputil_append_meter_config(&replies, &config);
        }
    }

    ofconn_send_replies(ofconn, &replies);
    ofpbuf_uninit(&bands);
    return 0;
}

Project: ovs
File: ofproto.c

handle_modify_meter(struct ofproto *ofproto, struct ofputil_meter_mod *mm)
{
    struct meter *meter = ofproto->meters[mm->meter.meter_id];
    enum ofperr error;
    uint32_t provider_meter_id;

    if (!meter) {
        return OFPERR_OFPMMFC_UNKNOWN_METER;
    }

    provider_meter_id = meter->provider_meter_id.uint32;
    error = ofproto->ofproto_class->meter_set(ofproto,
                                              &meter->provider_meter_id,
                                              &mm->meter);
    ovs_assert(meter->provider_meter_id.uint32 == provider_meter_id);
    if (!error) {
        meter_update(meter, &mm->meter);
    }
    return error;
}

Project: ovs
File: ofproto.c

handle_nxt_ct_flush_zone(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    const struct nx_zone_id *nzi = ofpmsg_body(oh);

    if (!is_all_zeros(nzi->zero, sizeof nzi->zero)) {
        return OFPERR_NXBRC_MUST_BE_ZERO;
    }

    uint16_t zone = ntohs(nzi->zone_id);
    if (ofproto->ofproto_class->ct_flush) {
        ofproto->ofproto_class->ct_flush(ofproto, &zone);
    } else {
        return EOPNOTSUPP;
    }

    return 0;
}

Project: ovs
File: ofproto.c

handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
                             const struct ofp_header *oh)
{
    const struct nx_flow_mod_table_id *msg = ofpmsg_body(oh);
    enum ofputil_protocol cur, next;

    cur = ofconn_get_protocol(ofconn);
    next = ofputil_protocol_set_tid(cur, msg->set != 0);
    ofconn_set_protocol(ofconn, next);

    return 0;
}

Project: ovs
File: ofproto.c

handle_nxt_get_async_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofputil_async_cfg ac = ofconn_get_async_config(ofconn);
    ofconn_send_reply(ofconn, ofputil_encode_get_async_reply(oh, &ac));

    return 0;
}

Project: ovs
File: ofproto.c

handle_nxt_resume(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_packet_in_private pin;
    enum ofperr error;

    error = ofputil_decode_packet_in_private(oh, false,
                                             ofproto_get_tun_tab(ofproto),
                                             &ofproto->vl_mff_map, &pin, NULL,
                                             NULL);
    if (error) {
        return error;
    }

    error = (ofproto->ofproto_class->nxt_resume
             ? ofproto->ofproto_class->nxt_resume(ofproto, &pin)
             : OFPERR_NXR_NOT_SUPPORTED);

    ofputil_packet_in_private_destroy(&pin);

    return error;
}

Project: ovs
File: ofproto.c

handle_nxt_set_async_config(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofputil_async_cfg basis = ofconn_get_async_config(ofconn);
    struct ofputil_async_cfg ac;
    enum ofperr error;

    error = ofputil_decode_set_async_config(oh, false, &basis, &ac);
    if (error) {
        return error;
    }

    ofconn_set_async_config(ofconn, &ac);
    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;
}

Project: ovs
File: ofproto.c

handle_nxt_set_controller_id(struct ofconn *ofconn,
                             const struct ofp_header *oh)
{
    const struct nx_controller_id *nci = ofpmsg_body(oh);

    if (!is_all_zeros(nci->zero, sizeof nci->zero)) {
        return OFPERR_NXBRC_MUST_BE_ZERO;
    }

    ofconn_set_controller_id(ofconn, ntohs(nci->controller_id));
    return 0;
}

Project: ovs
File: ofproto.c

handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
{
    const struct nx_set_flow_format *msg = ofpmsg_body(oh);
    enum ofputil_protocol cur, next;
    enum ofputil_protocol next_base;

    next_base = ofputil_nx_flow_format_to_protocol(ntohl(msg->format));
    if (!next_base) {
        return OFPERR_OFPBRC_EPERM;
    }

    cur = ofconn_get_protocol(ofconn);
    next = ofputil_protocol_set_base(cur, next_base);
    ofconn_set_protocol(ofconn, next);

    return 0;
}

Project: ovs
File: ofproto.c

handle_nxt_set_packet_in_format(struct ofconn *ofconn,
                                const struct ofp_header *oh)
{
    const struct nx_set_packet_in_format *msg = ofpmsg_body(oh);
    uint32_t format;

    format = ntohl(msg->format);
    if (!ofputil_packet_in_format_is_valid(format)) {
        return OFPERR_OFPBRC_EPERM;
    }

    ofconn_set_packet_in_format(ofconn, format);
    return 0;
}

Project: ovs
File: ofproto.c

handle_port_desc_stats_request(struct ofconn *ofconn,
                               const struct ofp_header *request)
{
    ofp_port_t port_no;
    enum ofperr error;

    error = ofputil_decode_port_desc_stats_request(request, &port_no);
    if (!error) {
        handle_port_request(ofconn, request, port_no, append_port_desc);
    }
    return error;
}

Project: ovs
File: ofproto.c

handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofputil_port_mod pm;
    struct ofport *port;
    enum ofperr error;

    error = reject_slave_controller(ofconn);
    if (error) {
        return error;
    }

    error = ofputil_decode_port_mod(oh, &pm, false);
    if (error) {
        return error;
    }

    error = port_mod_start(ofconn, &pm, &port);
    if (!error) {
        port_mod_finish(ofconn, &pm, port);
    }
    return error;
}

Project: ovs
File: ofproto.c

handle_port_request(struct ofconn *ofconn,
                    const struct ofp_header *request, ofp_port_t port_no,
                    void (*cb)(struct ofport *, struct ovs_list *replies))
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofport *port;
    struct ovs_list replies;

    ofpmp_init(&replies, request);
    if (port_no != OFPP_ANY) {
        port = ofproto_get_port(ofproto, port_no);
        if (port) {
            cb(port, &replies);
        }
    } else {
        HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
            cb(port, &replies);
        }
    }

    ofconn_send_replies(ofconn, &replies);
}

Project: ovs
File: ofproto.c

handle_port_stats_request(struct ofconn *ofconn,
                          const struct ofp_header *request)
{
    ofp_port_t port_no;
    enum ofperr error;

    error = ofputil_decode_port_stats_request(request, &port_no);
    if (!error) {
        handle_port_request(ofconn, request, port_no, append_port_stat);
    }
    return error;
}

Project: ovs
File: ofproto.c

handle_queue_get_config_request(struct ofconn *ofconn,
                                const struct ofp_header *oh)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ovs_list replies;
    struct ofport *port;
    ofp_port_t req_port;
    uint32_t req_queue;
    enum ofperr error;

    error = ofputil_decode_queue_get_config_request(oh, &req_port, &req_queue);
    if (error) {
        return error;
    }

    ofputil_start_queue_get_config_reply(oh, &replies);
    if (req_port == OFPP_ANY) {
        error = OFPERR_OFPQOFC_BAD_QUEUE;
        HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
            if (!handle_queue_get_config_request_for_port(port, req_queue,
                                                          &replies)) {
                error = 0;
            }
        }
    } else {
        port = ofproto_get_port(ofproto, req_port);
        error = (port
                 ? handle_queue_get_config_request_for_port(port, req_queue,
                                                            &replies)
                 : OFPERR_OFPQOFC_BAD_PORT);
    }
    if (!error) {
        ofconn_send_replies(ofconn, &replies);
    } else {
        ofpbuf_list_delete(&replies);
    }

    return error;
}

Project: ovs
File: ofproto.c

handle_queue_get_config_request_for_port(struct ofport *port, uint32_t queue,
                                         struct ovs_list *replies)
{
    struct smap details = SMAP_INITIALIZER(&details);
    if (queue != OFPQ_ALL) {
        int error = netdev_get_queue(port->netdev, queue, &details);
        switch (error) {
        case 0:
            put_queue_get_config_reply(port, queue, replies);
            break;
        case EOPNOTSUPP:
        case EINVAL:
            return OFPERR_OFPQOFC_BAD_QUEUE;
        default:
            return OFPERR_NXQOFC_QUEUE_ERROR;
        }
    } else {
        struct netdev_queue_dump queue_dump;
        uint32_t queue_id;

        NETDEV_QUEUE_FOR_EACH (&queue_id, &details, &queue_dump,
                               port->netdev) {
            put_queue_get_config_reply(port, queue_id, replies);
        }
    }
    smap_destroy(&details);
    return 0;
}

Project: ovs
File: ofproto.c

handle_queue_stats_dump_cb(uint32_t queue_id,
                           struct netdev_queue_stats *stats,
                           void *cbdata_)
{
    struct queue_stats_cbdata *cbdata = cbdata_;

    put_queue_stats(cbdata, queue_id, stats);
}

Project: ovs
File: ofproto.c

handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id,
                            struct queue_stats_cbdata *cbdata)
{
    cbdata->ofport = port;
    if (queue_id == OFPQ_ALL) {
        netdev_dump_queue_stats(port->netdev,
                                handle_queue_stats_dump_cb, cbdata);
    } else {
        struct netdev_queue_stats stats;

        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;
}

Project: ovs
File: ofproto.c

handle_queue_stats_request(struct ofconn *ofconn,
                           const struct ofp_header *rq)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct queue_stats_cbdata cbdata;
    struct ofport *port;
    enum ofperr error;
    struct ofputil_queue_stats_request oqsr;

    COVERAGE_INC(ofproto_queue_req);

    ofpmp_init(&cbdata.replies, rq);
    cbdata.now = time_msec();

    error = ofputil_decode_queue_stats_request(rq, &oqsr);
    if (error) {
        return error;
    }

    if (oqsr.port_no == OFPP_ANY) {
        error = OFPERR_OFPQOFC_BAD_QUEUE;
        HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
            if (!handle_queue_stats_for_port(port, oqsr.queue_id, &cbdata)) {
                error = 0;
            }
        }
    } else {
        port = ofproto_get_port(ofproto, oqsr.port_no);
        error = (port
                 ? handle_queue_stats_for_port(port, oqsr.queue_id, &cbdata)
                 : OFPERR_OFPQOFC_BAD_PORT);
    }
    if (!error) {
        ofconn_send_replies(ofconn, &cbdata.replies);
    } else {
        ofpbuf_list_delete(&cbdata.replies);
    }

    return error;
}

Project: ovs
File: ofproto.c

handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofputil_role_request request;
    struct ofputil_role_request reply;
    struct ofpbuf *buf;
    enum ofperr error;

    error = ofputil_decode_role_message(oh, &request);
    if (error) {
        return error;
    }

    if (request.role != OFPCR12_ROLE_NOCHANGE) {
        if (request.role != OFPCR12_ROLE_EQUAL
            && request.have_generation_id
            && !ofconn_set_master_election_id(ofconn, request.generation_id)) {
                return OFPERR_OFPRRFC_STALE;
        }

        ofconn_set_role(ofconn, request.role);
    }

    reply.role = ofconn_get_role(ofconn);
    reply.have_generation_id = ofconn_get_master_election_id(
        ofconn, &reply.generation_id);
    buf = ofputil_encode_role_reply(oh, &reply);
    ofconn_send_reply(ofconn, buf);

    return 0;
}

Project: ovs
File: ofproto.c

handle_set_config(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_switch_config config;
    enum ofperr error;

    error = ofputil_decode_set_config(oh, &config);
    if (error) {
        return error;
    }

    if (ofconn_get_type(ofconn) != OFCONN_PRIMARY
        || ofconn_get_role(ofconn) != OFPCR12_ROLE_SLAVE) {
        enum ofputil_frag_handling cur = ofproto->frag_handling;
        enum ofputil_frag_handling next = config.frag;

        if (cur != next) {
            if (ofproto->ofproto_class->set_frag_handling(ofproto, next)) {
                ofproto->frag_handling = next;
            } else {
                VLOG_WARN_RL(&rl, "%s: unsupported fragment handling mode %s",
                             ofproto->name,
                             ofputil_frag_handling_to_string(next));
            }
        }
    }

    if (config.invalid_ttl_to_controller >= 0) {
        ofconn_set_invalid_ttl_to_controller(ofconn,
                                             config.invalid_ttl_to_controller);
    }

    ofconn_set_miss_send_len(ofconn, config.miss_send_len);

    return 0;
}

Project: ovs
File: ofproto.c

handle_table_desc_request(struct ofconn *ofconn,
                          const struct ofp_header *request)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_table_desc *table_desc;
    struct ovs_list replies;
    size_t i;

    query_tables_desc(ofproto, &table_desc);
    ofpmp_init(&replies, request);
    for (i = 0; i < ofproto->n_tables; i++) {
        if (!(ofproto->tables[i].flags & OFTABLE_HIDDEN)) {
            ofputil_append_table_desc_reply(&table_desc[i], &replies,
                                            request->version);
        }
    }
    ofconn_send_replies(ofconn, &replies);
    free(table_desc);
    return 0;
}

Project: ovs
File: ofproto.c

handle_table_features_request(struct ofconn *ofconn,
                              const struct ofp_header *request)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofpbuf msg = ofpbuf_const_initializer(request,
                                                 ntohs(request->length));
    ofpraw_pull_assert(&msg);
    if (msg.size || ofpmp_more(request)) {
        return OFPERR_OFPTFFC_EPERM;
    }

    struct ofputil_table_features *features;
    query_tables(ofproto, &features, NULL);

    struct ovs_list replies;
    ofpmp_init(&replies, request);
    for (size_t i = 0; i < ofproto->n_tables; i++) {
        if (!(ofproto->tables[i].flags & OFTABLE_HIDDEN)) {
            ofputil_append_table_features_reply(&features[i], &replies);
        }
    }
    ofconn_send_replies(ofconn, &replies);

    free(features);

    return 0;
}

Project: ovs
File: ofproto.c

handle_table_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    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;
    }

    return table_mod(ofproto, &tm);
}

Project: ovs
File: ofproto.c

handle_table_stats_request(struct ofconn *ofconn,
                           const struct ofp_header *request)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_table_features *features;
    struct ofputil_table_stats *stats;
    struct ofpbuf *reply;
    size_t i;

    query_tables(ofproto, &features, &stats);

    reply = ofputil_encode_table_stats_reply(request);
    for (i = 0; i < ofproto->n_tables; i++) {
        if (!(ofproto->tables[i].flags & OFTABLE_HIDDEN)) {
            ofputil_append_table_stats_reply(reply, &stats[i], &features[i]);
        }
    }
    ofconn_send_reply(ofconn, reply);

    free(features);
    free(stats);

    return 0;
}

Project: ovs
File: ofproto.c

handle_tlv_table_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct tun_table *old_tab, *new_tab;
    struct ofputil_tlv_table_mod ttm;
    enum ofperr error;

    error = reject_slave_controller(ofconn);
    if (error) {
        return error;
    }

    error = ofputil_decode_tlv_table_mod(oh, &ttm);
    if (error) {
        return error;
    }

    old_tab = ovsrcu_get_protected(struct tun_table *, &ofproto->metadata_tab);
    error = tun_metadata_table_mod(&ttm, old_tab, &new_tab);
    if (!error) {
        ovs_mutex_lock(&ofproto->vl_mff_map.mutex);
        error = mf_vl_mff_map_mod_from_tun_metadata(&ofproto->vl_mff_map,
                                                    &ttm);
        ovs_mutex_unlock(&ofproto->vl_mff_map.mutex);
        if (!error) {
            ovsrcu_set(&ofproto->metadata_tab, new_tab);
            tun_metadata_postpone_free(old_tab);
        }
    }

    ofputil_uninit_tlv_table(&ttm.mappings);
    return error;
}

Project: ovs
File: ofproto.c

handle_tlv_table_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
    const struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
    struct ofputil_tlv_table_reply ttr;
    struct ofpbuf *b;

    tun_metadata_table_request(ofproto_get_tun_tab(ofproto), &ttr);

    b = ofputil_encode_tlv_table_reply(oh, &ttr);
    ofputil_uninit_tlv_table(&ttr.mappings);

    ofconn_send_reply(ofconn, b);
    return 0;
}

Project: ovs
File: ofproto.c

hash_cookie(ovs_be64 cookie)
{
    return hash_uint64((OVS_FORCE uint64_t)cookie);
}

Project: ovs
File: ofproto.c

init_ports(struct ofproto *p)
{
    struct ofproto_port_dump dump;
    struct ofproto_port ofproto_port;
    struct shash_node *node, *next;

    OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, p) {
        const char *name = ofproto_port.name;

        if (shash_find(&p->port_by_name, name)) {
            VLOG_WARN_RL(&rl, "%s: ignoring duplicate device %s in datapath",
                         p->name, name);
        } else {
            struct ofputil_phy_port pp;
            struct netdev *netdev;

            /* Check if an OpenFlow port number had been requested. */
            node = shash_find(&init_ofp_ports, name);
            if (node) {
                const struct iface_hint *iface_hint = node->data;
                simap_put(&p->ofp_requests, name,
                          ofp_to_u16(iface_hint->ofp_port));
            }

            netdev = ofport_open(p, &ofproto_port, &pp);
            if (netdev) {
                ofport_install(p, netdev, &pp);
                if (ofp_to_u16(ofproto_port.ofp_port) < p->max_ports) {
                    p->alloc_port_no = MAX(p->alloc_port_no,
                                           ofp_to_u16(ofproto_port.ofp_port));
                }
            }
        }
    }

    SHASH_FOR_EACH_SAFE(node, next, &init_ofp_ports) {
        struct iface_hint *iface_hint = node->data;

        if (!strcmp(iface_hint->br_name, p->name)) {
            free(iface_hint->br_name);
            free(iface_hint->br_type);
            free(iface_hint);
            shash_delete(&init_ofp_ports, node);
        }
    }

    return 0;
}

Project: ovs
File: ofproto.c

meter_create(const struct ofputil_meter_config *config,
             ofproto_meter_id provider_meter_id)
{
    struct meter *meter;

    meter = xzalloc(sizeof *meter);
    meter->provider_meter_id = provider_meter_id;
    meter->created = time_msec();
    ovs_list_init(&meter->rules);

    meter_update(meter, config);

    return meter;
}

Project: ovs
File: ofproto.c

meter_insert_rule(struct rule *rule)
{
    const struct rule_actions *a = rule_get_actions(rule);
    uint32_t meter_id = ofpacts_get_meter(a->ofpacts, a->ofpacts_len);
    struct meter *meter = rule->ofproto->meters[meter_id];

    ovs_list_insert(&meter->rules, &rule->meter_list_node);
}

Project: ovs
File: ofproto.c

meter_update(struct meter *meter, const struct ofputil_meter_config *config)
{
    free(meter->bands);

    meter->flags = config->flags;
    meter->n_bands = config->n_bands;
    meter->bands = xmemdup(config->bands,
                           config->n_bands * sizeof *meter->bands);
}

Project: ovs
File: ofproto.c

next_learn_with_delete(const struct rule_actions *actions,
                       const struct ofpact_learn *start)
{
    const struct ofpact *pos;

    for (pos = start ? ofpact_next(&start->ofpact) : actions->ofpacts;
         pos < ofpact_end(actions->ofpacts, actions->ofpacts_len);
         pos = ofpact_next(pos)) {
        if (pos->type == OFPACT_LEARN) {
            const struct ofpact_learn *learn = ofpact_get_LEARN(pos);
            if (learn->flags & NX_LEARN_F_DELETE_LEARNED) {
                return learn;
            }
        }
    }

    return NULL;
}

Project: ovs
File: ofproto.c

next_matching_table(const struct ofproto *ofproto,
                    const struct oftable *table, uint8_t table_id)
{
    return (table_id == 0xff
            ? next_visible_table(ofproto, (table - ofproto->tables) + 1)
            : NULL);
}

Project: ovs
File: ofproto.c

next_visible_table(const struct ofproto *ofproto, uint8_t table_id)
{
    struct oftable *table;

    for (table = &ofproto->tables[table_id];
         table < &ofproto->tables[ofproto->n_tables];
         table++) {
        if (!(table->flags & OFTABLE_HIDDEN)) {
            return table;
        }
    }

    return NULL;
}

Project: ovs
File: ofproto.c

ofport_destroy(struct ofport *port, bool del)
{
    if (port) {
        dealloc_ofp_port(port->ofproto, port->ofp_port);
        port->ofproto->ofproto_class->port_destruct(port, del);
        ofport_destroy__(port);
     }
}

Project: ovs
File: ofproto.c

ofport_destroy__(struct ofport *port)
{
    struct ofproto *ofproto = port->ofproto;
    const char *name = netdev_get_name(port->netdev);

    hmap_remove(&ofproto->ports, &port->hmap_node);
    shash_delete(&ofproto->port_by_name,
                 shash_find(&ofproto->port_by_name, name));

    netdev_close(port->netdev);
    ofproto->ofproto_class->port_dealloc(port);
}

Project: ovs
File: ofproto.c

ofport_equal(const struct ofputil_phy_port *a,
             const struct ofputil_phy_port *b)
{
    return (eth_addr_equals(a->hw_addr, b->hw_addr)
            && a->state == b->state
            && !((a->config ^ b->config) & OFPUTIL_PC_PORT_DOWN)
            && a->curr == b->curr
            && a->advertised == b->advertised
            && a->supported == b->supported
            && a->peer == b->peer
            && a->curr_speed == b->curr_speed
            && a->max_speed == b->max_speed);
}

Project: ovs
File: ofproto.c

ofport_install(struct ofproto *p,
               struct netdev *netdev, const struct ofputil_phy_port *pp)
{
    const char *netdev_name = netdev_get_name(netdev);
    struct ofport *ofport;
    int error;

    /* Create ofport. */
    ofport = p->ofproto_class->port_alloc();
    if (!ofport) {
        error = ENOMEM;
        goto error;
    }
    ofport->ofproto = p;
    ofport->netdev = netdev;
    ofport->change_seq = netdev_get_change_seq(netdev);
    ofport->pp = *pp;
    ofport->ofp_port = pp->port_no;
    ofport->created = time_msec();

    /* Add port to 'p'. */
    hmap_insert(&p->ports, &ofport->hmap_node,
                hash_ofp_port(ofport->ofp_port));
    shash_add(&p->port_by_name, netdev_name, ofport);

    update_mtu(p, ofport);

    /* Let the ofproto_class initialize its private data. */
    error = p->ofproto_class->port_construct(ofport);
    if (error) {
        goto error;
    }
    connmgr_send_port_status(p->connmgr, NULL, pp, OFPPR_ADD);
    return 0;

error:
    VLOG_WARN_RL(&rl, "%s: could not add port %s (%s)",
                 p->name, netdev_name, ovs_strerror(error));
    if (ofport) {
        ofport_destroy__(ofport);
    } else {
        netdev_close(netdev);
    }
    return error;
}

Project: ovs
File: ofproto.c

ofport_is_internal_or_patch(const struct ofproto *p, const struct ofport *port)
{
    return !strcmp(netdev_get_type(port->netdev),
                   ofproto_port_open_type(p->type, "internal")) ||
           !strcmp(netdev_get_type(port->netdev),
                   ofproto_port_open_type(p->type, "patch"));
}

Project: ovs
File: ofproto.c

ofport_is_mtu_overridden(const struct ofproto *p, const struct ofport *port)
{
    return ofport_is_internal_or_patch(p, port)
           && !netdev_mtu_is_user_config(port->netdev);
}

Project: ovs
File: ofproto.c

ofport_modified(struct ofport *port, struct ofputil_phy_port *pp)
{
    port->pp.hw_addr = pp->hw_addr;
    port->pp.config = ((port->pp.config & ~OFPUTIL_PC_PORT_DOWN)
                        | (pp->config & OFPUTIL_PC_PORT_DOWN));
    port->pp.state = ((port->pp.state & ~OFPUTIL_PS_LINK_DOWN)
                      | (pp->state & OFPUTIL_PS_LINK_DOWN));
    port->pp.curr = pp->curr;
    port->pp.advertised = pp->advertised;
    port->pp.supported = pp->supported;
    port->pp.peer = pp->peer;
    port->pp.curr_speed = pp->curr_speed;
    port->pp.max_speed = pp->max_speed;

    connmgr_send_port_status(port->ofproto->connmgr, NULL,
                             &port->pp, OFPPR_MODIFY);
}

Project: ovs
File: ofproto.c

ofport_open(struct ofproto *ofproto,
            struct ofproto_port *ofproto_port,
            struct ofputil_phy_port *pp)
{
    enum netdev_flags flags;
    struct netdev *netdev;
    int error;

    error = netdev_open(ofproto_port->name, ofproto_port->type, &netdev);
    if (error) {
        VLOG_WARN_RL(&rl, "%s: ignoring port %s (%"PRIu32") because netdev %s "
                     "cannot be opened (%s)",
                     ofproto->name,
                     ofproto_port->name, ofproto_port->ofp_port,
                     ofproto_port->name, ovs_strerror(error));
        return NULL;
    }

    if (ofproto_port->ofp_port == OFPP_NONE) {
        if (!strcmp(ofproto->name, ofproto_port->name)) {
            ofproto_port->ofp_port = OFPP_LOCAL;
        } else {
            ofproto_port->ofp_port = alloc_ofp_port(ofproto,
                                                    ofproto_port->name);
        }
    }
    pp->port_no = ofproto_port->ofp_port;
    netdev_get_etheraddr(netdev, &pp->hw_addr);
    ovs_strlcpy(pp->name, ofproto_port->name, sizeof pp->name);
    netdev_get_flags(netdev, &flags);
    pp->config = flags & NETDEV_UP ? 0 : OFPUTIL_PC_PORT_DOWN;
    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) / 1000;
    pp->max_speed = netdev_features_to_bps(pp->supported, 0) / 1000;

    return netdev;
}

Project: ovs
File: ofproto.c

ofport_remove(struct ofport *ofport)
{
    struct ofproto *p = ofport->ofproto;
    bool is_mtu_overridden = ofport_is_mtu_overridden(p, ofport);

    connmgr_send_port_status(ofport->ofproto->connmgr, NULL, &ofport->pp,
                             OFPPR_DELETE);
    ofport_destroy(ofport, true);
    if (!is_mtu_overridden) {
        update_mtu_ofproto(p);
    }
}

Project: ovs
File: ofproto.c

ofport_remove_usage(struct ofproto *ofproto, ofp_port_t ofp_port)
{
    struct ofport_usage *usage;
    HMAP_FOR_EACH_IN_BUCKET (usage, hmap_node, hash_ofp_port(ofp_port),
                             &ofproto->ofport_usage) {
        if (usage->ofp_port == ofp_port) {
            hmap_remove(&ofproto->ofport_usage, &usage->hmap_node);
            free(usage);
            break;
        }
    }
}

Project: ovs
File: ofproto.c

ofport_set_usage(struct ofproto *ofproto, ofp_port_t ofp_port,
                 long long int last_used)
{
    struct ofport_usage *usage;
    HMAP_FOR_EACH_IN_BUCKET (usage, hmap_node, hash_ofp_port(ofp_port),
                             &ofproto->ofport_usage) {
        if (usage->ofp_port == ofp_port) {
            usage->last_used = last_used;
            return;
        }
    }
    ovs_assert(last_used == LLONG_MAX);

    usage = xmalloc(sizeof *usage);
    usage->ofp_port = ofp_port;
    usage->last_used = last_used;
    hmap_insert(&ofproto->ofport_usage, &usage->hmap_node,
                hash_ofp_port(ofp_port));
}

Project: ovs
File: ofproto.c

ofproto_aa_mapping_register(struct ofproto *ofproto, void *aux,
                            const struct aa_mapping_settings *s)
{
    if (!ofproto->ofproto_class->aa_mapping_set) {
        return EOPNOTSUPP;
    }
    ofproto->ofproto_class->aa_mapping_set(ofproto, aux, s);
    return 0;
}

Project: ovs
File: ofproto.c

ofproto_aa_vlan_get_queue_size(struct ofproto *ofproto)
{
    if (!ofproto->ofproto_class->aa_vlan_get_queue_size) {
        return EOPNOTSUPP;
    }
    return ofproto->ofproto_class->aa_vlan_get_queue_size(ofproto);
}

Project: ovs
File: ofproto.c

ofproto_aa_vlan_get_queued(struct ofproto *ofproto,
                           struct ovs_list *list)
{
    if (!ofproto->ofproto_class->aa_vlan_get_queued) {
        return EOPNOTSUPP;
    }
    ofproto->ofproto_class->aa_vlan_get_queued(ofproto, list);
    return 0;
}

Project: ovs
File: ofproto.c

ofproto_bump_tables_version(struct ofproto *ofproto)
{
    ++ofproto->tables_version;
    ofproto->ofproto_class->set_tables_version(ofproto,
                                               ofproto->tables_version);
}

Project: ovs
File: ofproto.c

ofproto_bundle_register(struct ofproto *ofproto, void *aux,
                        const struct ofproto_bundle_settings *s)
{
    return (ofproto->ofproto_class->bundle_set
            ? ofproto->ofproto_class->bundle_set(ofproto, aux, s)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_bundle_unregister(struct ofproto *ofproto, void *aux)
{
    return ofproto_bundle_register(ofproto, aux, NULL);
}

Project: ovs
File: ofproto.c

ofproto_class_find__(const char *type)
{
    size_t i;

    for (i = 0; i < n_ofproto_classes; i++) {
        const struct ofproto_class *class = ofproto_classes[i];
        struct sset types;
        bool found;

        sset_init(&types);
        class->enumerate_types(&types);
        found = sset_contains(&types, type);
        sset_destroy(&types);

        if (found) {
            return class;
        }
    }
    VLOG_WARN("unknown datapath type %s", type);
    return NULL;
}

Project: ovs
File: ofproto.c

ofproto_class_register(const struct ofproto_class *new_class)
{
    size_t i;

    for (i = 0; i < n_ofproto_classes; i++) {
        if (ofproto_classes[i] == new_class) {
            return EEXIST;
        }
    }

    if (n_ofproto_classes >= allocated_ofproto_classes) {
        ofproto_classes = x2nrealloc(ofproto_classes,
                                     &allocated_ofproto_classes,
                                     sizeof *ofproto_classes);
    }
    ofproto_classes[n_ofproto_classes++] = new_class;
    return 0;
}

Project: ovs
File: ofproto.c

ofproto_class_unregister(const struct ofproto_class *class)
{
    size_t i;

    for (i = 0; i < n_ofproto_classes; i++) {
        if (ofproto_classes[i] == class) {
            for (i++; i < n_ofproto_classes; i++) {
                ofproto_classes[i - 1] = ofproto_classes[i];
            }
            n_ofproto_classes--;
            return 0;
        }
    }
    VLOG_WARN("attempted to unregister an ofproto class that is not "
              "registered");
    return EAFNOSUPPORT;
}

Project: ovs
File: ofproto.c

ofproto_configure_table(struct ofproto *ofproto, int table_id,
                        const struct ofproto_table_settings *s)
{
    struct oftable *table;

    ovs_assert(table_id >= 0 && table_id < ofproto->n_tables);
    table = &ofproto->tables[table_id];

    oftable_set_name(table, s->name);

    if (table->flags & OFTABLE_READONLY) {
        return;
    }

    if (classifier_set_prefix_fields(&table->cls,
                                     s->prefix_fields, s->n_prefix_fields)) {
        /* XXX: Trigger revalidation. */
    }

    ovs_mutex_lock(&ofproto_mutex);
    unsigned int new_eviction = (s->enable_eviction
                                 ? table->eviction | EVICTION_CLIENT
                                 : table->eviction & ~EVICTION_CLIENT);
    oftable_configure_eviction(table, new_eviction, s->groups, s->n_groups);
    table->max_flows = s->max_flows;
    evict_rules_from_table(table);
    ovs_mutex_unlock(&ofproto_mutex);
}

Project: ovs
File: ofproto.c

ofproto_delete(const char *name, const char *type)
{
    const struct ofproto_class *class = ofproto_class_find__(type);
    return (!class ? EAFNOSUPPORT
            : !class->del ? EACCES
            : class->del(type, name));
}

Project: ovs
File: ofproto.c

ofproto_enumerate_names(const char *type, struct sset *names)
{
    const struct ofproto_class *class = ofproto_class_find__(type);
    return class ? class->enumerate_names(type, names) : EAFNOSUPPORT;
}

Project: ovs
File: ofproto.c

ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm)
{
    enum ofperr error = 0;

    /* ofm->temp_rule is our reference to the learned rule.  We have a
     * reference to an existing rule, if it already was in the classifier,
     * otherwise we may have a fresh rule that we need to insert. */
    struct rule *rule = ofm->temp_rule;
    if (!rule) {
        return OFPERR_OFPFMFC_UNKNOWN;
    }

    /* Create a new rule if the current one has been removed from the
     * classifier.  We need to do this since RCU does not allow a current rule
     * to be reinserted before all threads have quiesced.
     *
     * It is possible that the rule is removed asynchronously, e.g., right
     * after we have read the 'rule->state' below.  In this case the next time
     * this function is executed the rule will be reinstated. */
    if (rule->state == RULE_REMOVED) {
        struct cls_rule cr;

        cls_rule_clone(&cr, &rule->cr);
        ovs_mutex_lock(&rule->mutex);
        error = ofproto_rule_create(rule->ofproto, &cr, rule->table_id,
                                    rule->flow_cookie,
                                    rule->idle_timeout,
                                    rule->hard_timeout, rule->flags,
                                    rule->importance,
                                    rule->actions->ofpacts,
                                    rule->actions->ofpacts_len,
                                    rule->match_tlv_bitmap,
                                    rule->ofpacts_tlv_bitmap,
                                    &ofm->temp_rule);
        ovs_mutex_unlock(&rule->mutex);
        if (!error) {
            ofproto_rule_unref(rule);   /* Release old reference. */
        }
    } else {
        /* Refresh the existing rule. */
        ovs_mutex_lock(&rule->mutex);
        rule->modified = time_msec();
        ovs_mutex_unlock(&rule->mutex);
    }
    return error;
}

Project: ovs
File: ofproto.c

ofproto_flow_mod_uninit(struct ofproto_flow_mod *ofm)
{
    if (ofm->temp_rule) {
        ofproto_rule_unref(ofm->temp_rule);
        ofm->temp_rule = NULL;
    }
    if (ofm->criteria.version != OVS_VERSION_NOT_REMOVED) {
        rule_criteria_destroy(&ofm->criteria);
    }
    if (ofm->conjs) {
        free(ofm->conjs);
        ofm->conjs = NULL;
        ofm->n_conjs = 0;
    }
}

Project: ovs
File: ofproto.c

ofproto_flush_flows(struct ofproto *ofproto)
{
    COVERAGE_INC(ofproto_flush);
    ofproto_flush__(ofproto);
    connmgr_flushed(ofproto->connmgr);
}

Project: ovs
File: ofproto.c

ofproto_free_ofproto_controller_info(struct shash *info)
{
    connmgr_free_controller_info(info);
}

Project: ovs
File: ofproto.c

ofproto_get_all_flows(struct ofproto *p, struct ds *results)
{
    struct oftable *table;

    OFPROTO_FOR_EACH_TABLE (table, p) {
        struct rule *rule;

        CLS_FOR_EACH (rule, cr, &table->cls) {
            flow_stats_ds(p, rule, results);
        }
    }
}

Project: ovs
File: ofproto.c

ofproto_get_datapath_id(const struct ofproto *ofproto)
{
    return ofproto->datapath_id;
}

Project: ovs
File: ofproto.c

ofproto_get_flow_restore_wait(void)
{
    return flow_restore_wait;
}

Project: ovs
File: ofproto.c

ofproto_get_ipfix_stats(struct ofproto *ofproto,
                        bool bridge_ipfix,
                        struct ovs_list *replies)
{
    int error;

    if (ofproto->ofproto_class->get_ipfix_stats) {
        error = ofproto->ofproto_class->get_ipfix_stats(ofproto,
                                                          bridge_ipfix,
                                                          replies);
    } else {
        error = EOPNOTSUPP;
    }

    return error;
}

Project: ovs
File: ofproto.c

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));

    n_rules = 0;
    OFPROTO_FOR_EACH_TABLE (table, ofproto) {
        n_rules += table->n_flows;
    }
    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);
}

Project: ovs
File: ofproto.c

ofproto_get_n_tables(const struct ofproto *ofproto)
{
    return ofproto->n_tables;
}

Project: ovs
File: ofproto.c

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;
}

Project: ovs
File: ofproto.c

ofproto_get_netflow_ids(const struct ofproto *ofproto,
                        uint8_t *engine_type, uint8_t *engine_id)
{
    ofproto->ofproto_class->get_netflow_ids(ofproto, engine_type, engine_id);
}

Project: ovs
File: ofproto.c

ofproto_get_ofproto_controller_info(const struct ofproto *ofproto,
                                    struct shash *info)
{
    connmgr_get_controller_info(ofproto->connmgr, info);
}

Project: ovs
File: ofproto.c

ofproto_get_port(const struct ofproto *ofproto, ofp_port_t ofp_port)
{
    struct ofport *port;

    HMAP_FOR_EACH_IN_BUCKET (port, hmap_node, hash_ofp_port(ofp_port),
                             &ofproto->ports) {
        if (port->ofp_port == ofp_port) {
            return port;
        }
    }
    return NULL;
}

Project: ovs
File: ofproto.c

ofproto_get_rstp_status(struct ofproto *ofproto,
                        struct ofproto_rstp_status *s)
{
    if (!ofproto->ofproto_class->get_rstp_status) {
        return EOPNOTSUPP;
    }
    ofproto->ofproto_class->get_rstp_status(ofproto, s);
    return 0;
}

Project: ovs
File: ofproto.c

ofproto_get_snoops(const struct ofproto *ofproto, struct sset *snoops)
{
    connmgr_get_snoops(ofproto->connmgr, snoops);
}

Project: ovs
File: ofproto.c

ofproto_get_stp_status(struct ofproto *ofproto,
                       struct ofproto_stp_status *s)
{
    return (ofproto->ofproto_class->get_stp_status
            ? ofproto->ofproto_class->get_stp_status(ofproto, s)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_group_exists(const struct ofproto *ofproto, uint32_t group_id)
{
    return ofproto_group_lookup__(ofproto, group_id, OVS_VERSION_MAX) != NULL;
}

Project: ovs
File: ofproto.c

ofproto_group_lookup(const struct ofproto *ofproto, uint32_t group_id,
                     ovs_version_t version, bool take_ref)
{
    struct ofgroup *group;

    group = ofproto_group_lookup__(ofproto, group_id, version);
    if (group && take_ref) {
        /* Not holding a lock, so it is possible that another thread releases
         * the last reference just before we manage to get one. */
        return ofproto_group_try_ref(group) ? group : NULL;
    }
    return group;
}

Project: ovs
File: ofproto.c

ofproto_group_lookup__(const struct ofproto *ofproto, uint32_t group_id,
                       ovs_version_t version)
{
    struct ofgroup *group;

    CMAP_FOR_EACH_WITH_HASH (group, cmap_node, hash_int(group_id, 0),
                             &ofproto->groups) {
        if (group->group_id == group_id
            && versions_visible_in_version(&group->versions, version)) {
            return group;
        }
    }

    return NULL;
}

Project: ovs
File: ofproto.c

ofproto_group_ref(struct ofgroup *group)
{
    if (group) {
        ovs_refcount_ref(&group->ref_count);
    }
}

Project: ovs
File: ofproto.c

ofproto_group_try_ref(struct ofgroup *group)
{
    if (group) {
        return ovs_refcount_try_ref_rcu(&group->ref_count);
    }
    return false;
}

Project: ovs
File: ofproto.c

ofproto_has_snoops(const struct ofproto *ofproto)
{
    return connmgr_has_snoops(ofproto->connmgr);
}

Project: ovs
File: ofproto.c

ofproto_init(const struct shash *iface_hints)
{
    struct shash_node *node;
    size_t i;

    ofproto_class_register(&ofproto_dpif_class);

    /* Make a local copy, since we don't own 'iface_hints' elements. */
    SHASH_FOR_EACH(node, iface_hints) {
        const struct iface_hint *orig_hint = node->data;
        struct iface_hint *new_hint = xmalloc(sizeof *new_hint);
        const char *br_type = ofproto_normalize_type(orig_hint->br_type);

        new_hint->br_name = xstrdup(orig_hint->br_name);
        new_hint->br_type = xstrdup(br_type);
        new_hint->ofp_port = orig_hint->ofp_port;

        shash_add(&init_ofp_ports, node->name, new_hint);
    }

    for (i = 0; i < n_ofproto_classes; i++) {
        ofproto_classes[i]->init(&init_ofp_ports);
    }

    ofproto_unixctl_init();
}

Project: ovs
File: ofproto.c

ofproto_init_max_ports(struct ofproto *ofproto, uint16_t max_ports)
{
    ovs_assert(max_ports <= ofp_to_u16(OFPP_MAX));
    ofproto->max_ports = max_ports;
}

Project: ovs
File: ofproto.c

ofproto_init_tables(struct ofproto *ofproto, int n_tables)
{
    struct oftable *table;

    ovs_assert(!ofproto->n_tables);
    ovs_assert(n_tables >= 1 && n_tables <= 255);

    ofproto->n_tables = n_tables;
    ofproto->tables = xmalloc(n_tables * sizeof *ofproto->tables);
    OFPROTO_FOR_EACH_TABLE (table, ofproto) {
        oftable_init(table);
    }
}

Project: ovs
File: ofproto.c

ofproto_is_alive(const struct ofproto *p)
{
    return connmgr_has_controllers(p->connmgr);
}

Project: ovs
File: ofproto.c

ofproto_is_mirror_output_bundle(const struct ofproto *ofproto, void *aux)
{
    return (ofproto->ofproto_class->is_mirror_output_bundle
            ? ofproto->ofproto_class->is_mirror_output_bundle(ofproto, aux)
            : false);
}

Project: ovs
File: ofproto.c

ofproto_lookup(const char *name)
{
    struct ofproto *ofproto;

    HMAP_FOR_EACH_WITH_HASH (ofproto, hmap_node, hash_string(name, 0),
                             &all_ofprotos) {
        if (!strcmp(ofproto->name, name)) {
            return ofproto;
        }
    }
    return NULL;
}

Project: ovs
File: ofproto.c

ofproto_mirror_get_stats(struct ofproto *ofproto, void *aux,
                         uint64_t *packets, uint64_t *bytes)
{
    if (!ofproto->ofproto_class->mirror_get_stats) {
        *packets = *bytes = UINT64_MAX;
        return EOPNOTSUPP;
    }

    return ofproto->ofproto_class->mirror_get_stats(ofproto, aux,
                                                    packets, bytes);
}

Project: ovs
File: ofproto.c

ofproto_mirror_register(struct ofproto *ofproto, void *aux,
                        const struct ofproto_mirror_settings *s)
{
    return (ofproto->ofproto_class->mirror_set
            ? ofproto->ofproto_class->mirror_set(ofproto, aux, s)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_mirror_unregister(struct ofproto *ofproto, void *aux)
{
    return ofproto_mirror_register(ofproto, aux, NULL);
}

Project: ovs
File: ofproto.c

ofproto_packet_out_init(struct ofproto *ofproto,
                        struct ofconn *ofconn,
                        struct ofproto_packet_out *opo,
                        const struct ofputil_packet_out *po)
{
    enum ofperr error;

    if (ofp_to_u16(po->in_port) >= ofproto->max_ports
        && ofp_to_u16(po->in_port) < ofp_to_u16(OFPP_MAX)) {
        return OFPERR_OFPBRC_BAD_PORT;
    }

    /* Get payload. */
    if (po->buffer_id != UINT32_MAX) {
        return OFPERR_OFPBRC_BUFFER_UNKNOWN;
    }

    /* Ensure that the L3 header is 32-bit aligned. */
    opo->packet = dp_packet_clone_data_with_headroom(po->packet,
                                                     po->packet_len, 2);
    /* Store struct flow. */
    opo->flow = xmalloc(sizeof *opo->flow);
    flow_extract(opo->packet, opo->flow);
    opo->flow->in_port.ofp_port = po->in_port;

    /* Check actions like for flow mods.  We pass a 'table_id' of 0 to
     * ofproto_check_consistency(), which isn't strictly correct because these
     * actions aren't in any table.  This is OK as 'table_id' is only used to
     * check instructions (e.g., goto-table), which can't appear on the action
     * list of a packet-out. */
    error = ofpacts_check_consistency(po->ofpacts, po->ofpacts_len,
                                      opo->flow,
                                      u16_to_ofp(ofproto->max_ports), 0,
                                      ofproto->n_tables,
                                      ofconn_get_protocol(ofconn));
    if (error) {
        dp_packet_delete(opo->packet);
        free(opo->flow);
        return error;
    }

    opo->ofpacts = po->ofpacts;
    opo->ofpacts_len = po->ofpacts_len;

    opo->aux = NULL;
    return 0;
}

Project: ovs
File: ofproto.c

ofproto_packet_out_uninit(struct ofproto_packet_out *opo)
{
    dp_packet_delete(opo->packet);
    opo->packet = NULL;
    free(opo->flow);
    opo->flow = NULL;
    free(opo->ofpacts);
    opo->ofpacts = NULL;
    opo->ofpacts_len = 0;
    ovs_assert(!opo->aux);
}

Project: ovs
File: ofproto.c

ofproto_port_bfd_status_changed(struct ofproto *ofproto, ofp_port_t ofp_port)
{
    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
    return (ofport && ofproto->ofproto_class->bfd_status_changed
            ? ofproto->ofproto_class->bfd_status_changed(ofport)
            : true);
}

Project: ovs
File: ofproto.c

ofproto_port_clone(struct ofproto_port *port, const struct ofproto_port *old)
{
    port->name = xstrdup(old->name);
    port->type = xstrdup(old->type);
    port->ofp_port = old->ofp_port;
}

Project: ovs
File: ofproto.c

ofproto_port_destroy(struct ofproto_port *ofproto_port)
{
    free(ofproto_port->name);
    free(ofproto_port->type);
}

Project: ovs
File: ofproto.c

ofproto_port_dump_done(struct ofproto_port_dump *dump)
{
    const struct ofproto *ofproto = dump->ofproto;
    if (!dump->error) {
        dump->error = ofproto->ofproto_class->port_dump_done(ofproto,
                                                             dump->state);
    }
    return dump->error == EOF ? 0 : dump->error;
}

Project: ovs
File: ofproto.c

ofproto_port_dump_next(struct ofproto_port_dump *dump,
                       struct ofproto_port *port)
{
    const struct ofproto *ofproto = dump->ofproto;

    if (dump->error) {
        return false;
    }

    dump->error = ofproto->ofproto_class->port_dump_next(ofproto, dump->state,
                                                         port);
    if (dump->error) {
        ofproto->ofproto_class->port_dump_done(ofproto, dump->state);
        return false;
    }
    return true;
}

Project: ovs
File: ofproto.c

ofproto_port_dump_start(struct ofproto_port_dump *dump,
                        const struct ofproto *ofproto)
{
    dump->ofproto = ofproto;
    dump->error = ofproto->ofproto_class->port_dump_start(ofproto,
                                                          &dump->state);
}

Project: ovs
File: ofproto.c

ofproto_port_get_bfd_status(struct ofproto *ofproto, ofp_port_t ofp_port,
                            struct smap *status)
{
    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
    return (ofport && ofproto->ofproto_class->get_bfd_status
            ? ofproto->ofproto_class->get_bfd_status(ofport, status)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_port_get_cfm_status(const struct ofproto *ofproto, ofp_port_t ofp_port,
                            struct 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)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_port_get_lacp_stats(const struct ofport *port, struct lacp_slave_stats *stats)
{
    struct ofproto *ofproto = port->ofproto;
    int error;

    if (ofproto->ofproto_class->port_get_lacp_stats) {
        error = ofproto->ofproto_class->port_get_lacp_stats(port, stats);
    } else {
        error = EOPNOTSUPP;
    }

    return error;
}

Project: ovs
File: ofproto.c

ofproto_port_get_rstp_status(struct ofproto *ofproto, ofp_port_t ofp_port,
                             struct ofproto_port_rstp_status *s)
{
    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
    if (!ofport) {
        VLOG_WARN_RL(&rl, "%s: cannot get RSTP status on nonexistent "
                "port %"PRIu32, ofproto->name, ofp_port);
        return ENODEV;
    }

    if (!ofproto->ofproto_class->get_rstp_port_status) {
        return  EOPNOTSUPP;
    }
    ofproto->ofproto_class->get_rstp_port_status(ofport, s);
    return 0;
}

Project: ovs
File: ofproto.c

ofproto_port_get_stats(const struct ofport *port, struct netdev_stats *stats)
{
    struct ofproto *ofproto = port->ofproto;
    int error;

    if (ofproto->ofproto_class->port_get_stats) {
        error = ofproto->ofproto_class->port_get_stats(port, stats);
    } else {
        error = EOPNOTSUPP;
    }

    return error;
}

Project: ovs
File: ofproto.c

ofproto_port_get_stp_stats(struct ofproto *ofproto, ofp_port_t ofp_port,
                           struct ofproto_port_stp_stats *s)
{
    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
    if (!ofport) {
        VLOG_WARN_RL(&rl, "%s: cannot get STP stats on nonexistent "
                     "port %"PRIu32, ofproto->name, ofp_port);
        return ENODEV;
    }

    return (ofproto->ofproto_class->get_stp_port_stats
            ? ofproto->ofproto_class->get_stp_port_stats(ofport, s)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_port_get_stp_status(struct ofproto *ofproto, ofp_port_t ofp_port,
                            struct ofproto_port_stp_status *s)
{
    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
    if (!ofport) {
        VLOG_WARN_RL(&rl, "%s: cannot get STP status on nonexistent "
                     "port %"PRIu32, ofproto->name, ofp_port);
        return ENODEV;
    }

    return (ofproto->ofproto_class->get_stp_port_status
            ? ofproto->ofproto_class->get_stp_port_status(ofport, s)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_port_is_lacp_current(struct ofproto *ofproto, ofp_port_t ofp_port)
{
    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
    return (ofport && ofproto->ofproto_class->port_is_lacp_current
            ? ofproto->ofproto_class->port_is_lacp_current(ofport)
            : -1);
}

Project: ovs
File: ofproto.c

ofproto_port_open_type(const char *datapath_type, const char *port_type)
{
    const struct ofproto_class *class;

    datapath_type = ofproto_normalize_type(datapath_type);
    class = ofproto_class_find__(datapath_type);
    if (!class) {
        return port_type;
    }

    return (class->port_open_type
            ? class->port_open_type(datapath_type, port_type)
            : port_type);
}

Project: ovs
File: ofproto.c

ofproto_port_query_by_name(const struct ofproto *ofproto, const char *devname,
                           struct ofproto_port *port)
{
    int error;

    error = ofproto->ofproto_class->port_query_by_name(ofproto, devname, port);
    if (error) {
        memset(port, 0, sizeof *port);
    }
    return error;
}

Project: ovs
File: ofproto.c

ofproto_port_set_bfd(struct ofproto *ofproto, ofp_port_t ofp_port,
                     const struct smap *cfg)
{
    struct ofport *ofport;
    int error;

    ofport = ofproto_get_port(ofproto, ofp_port);
    if (!ofport) {
        VLOG_WARN("%s: cannot configure bfd on nonexistent port %"PRIu32,
                  ofproto->name, ofp_port);
        return;
    }

    error = (ofproto->ofproto_class->set_bfd
             ? ofproto->ofproto_class->set_bfd(ofport, cfg)
             : EOPNOTSUPP);
    if (error) {
        VLOG_WARN("%s: bfd configuration on port %"PRIu32" (%s) failed (%s)",
                  ofproto->name, ofp_port, netdev_get_name(ofport->netdev),
                  ovs_strerror(error));
    }
}

Project: ovs
File: ofproto.c

ofproto_port_set_cfm(struct ofproto *ofproto, ofp_port_t ofp_port,
                     const struct cfm_settings *s)
{
    struct ofport *ofport;
    int error;

    ofport = ofproto_get_port(ofproto, ofp_port);
    if (!ofport) {
        VLOG_WARN("%s: cannot configure CFM on nonexistent port %"PRIu32,
                  ofproto->name, ofp_port);
        return;
    }

    /* XXX: For configuration simplicity, we only support one remote_mpid
     * outside of the CFM module.  It's not clear if this is the correct long
     * term solution or not. */
    error = (ofproto->ofproto_class->set_cfm
             ? ofproto->ofproto_class->set_cfm(ofport, s)
             : EOPNOTSUPP);
    if (error) {
        VLOG_WARN("%s: CFM configuration on port %"PRIu32" (%s) failed (%s)",
                  ofproto->name, ofp_port, netdev_get_name(ofport->netdev),
                  ovs_strerror(error));
    }
}

Project: ovs
File: ofproto.c

ofproto_port_set_config(struct ofproto *ofproto, ofp_port_t ofp_port,
                        const struct smap *cfg)
{
    struct ofport *ofport;
    int error;

    ofport = ofproto_get_port(ofproto, ofp_port);
    if (!ofport) {
        VLOG_WARN("%s: cannot configure datapath on nonexistent port %"PRIu32,
                  ofproto->name, ofp_port);
        return;
    }

    error = (ofproto->ofproto_class->port_set_config
             ? ofproto->ofproto_class->port_set_config(ofport, cfg)
             : EOPNOTSUPP);
    if (error) {
        VLOG_WARN("%s: datapath configuration on port %"PRIu32
                  " (%s) failed (%s)",
                  ofproto->name, ofp_port, netdev_get_name(ofport->netdev),
                  ovs_strerror(error));
    }
}

Project: ovs
File: ofproto.c

ofproto_port_set_lldp(struct ofproto *ofproto,
                      ofp_port_t ofp_port,
                      const struct smap *cfg)
{
    struct ofport *ofport;
    int error;

    ofport = ofproto_get_port(ofproto, ofp_port);
    if (!ofport) {
        VLOG_WARN("%s: cannot configure LLDP on nonexistent port %"PRIu32,
                  ofproto->name, ofp_port);
        return;
    }
    error = (ofproto->ofproto_class->set_lldp
             ? ofproto->ofproto_class->set_lldp(ofport, cfg)
             : EOPNOTSUPP);
    if (error) {
        VLOG_WARN("%s: lldp configuration on port %"PRIu32" (%s) failed (%s)",
                  ofproto->name, ofp_port, netdev_get_name(ofport->netdev),
                  ovs_strerror(error));
    }
}

Project: ovs
File: ofproto.c

ofproto_port_set_mcast_snooping(struct ofproto *ofproto, void *aux,
                           const struct ofproto_mcast_snooping_port_settings *s)
{
    return (ofproto->ofproto_class->set_mcast_snooping_port
            ? ofproto->ofproto_class->set_mcast_snooping_port(ofproto, aux, s)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_port_set_queues(struct ofproto *ofproto, ofp_port_t ofp_port,
                        const struct ofproto_port_queue *queues,
                        size_t n_queues)
{
    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);

    if (!ofport) {
        VLOG_WARN("%s: cannot set queues on nonexistent port %"PRIu32,
                  ofproto->name, ofp_port);
        return ENODEV;
    }

    return (ofproto->ofproto_class->set_queues
            ? ofproto->ofproto_class->set_queues(ofport, queues, n_queues)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_port_set_state(struct ofport *port, enum ofputil_port_state state)
{
    if (port->pp.state != state) {
        port->pp.state = state;
        connmgr_send_port_status(port->ofproto->connmgr, NULL,
                                 &port->pp, OFPPR_MODIFY);
    }
}

Project: ovs
File: ofproto.c

ofproto_port_set_stp(struct ofproto *ofproto, ofp_port_t ofp_port,
                     const struct ofproto_port_stp_settings *s)
{
    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
    if (!ofport) {
        VLOG_WARN("%s: cannot configure STP on nonexistent port %"PRIu32,
                  ofproto->name, ofp_port);
        return ENODEV;
    }

    return (ofproto->ofproto_class->set_stp_port
            ? ofproto->ofproto_class->set_stp_port(ofport, s)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_port_unregister(struct ofproto *ofproto, ofp_port_t ofp_port)
{
    struct ofport *port = ofproto_get_port(ofproto, ofp_port);
    if (port) {
        if (port->ofproto->ofproto_class->set_stp_port) {
            port->ofproto->ofproto_class->set_stp_port(port, NULL);
        }
        if (port->ofproto->ofproto_class->set_rstp_port) {
            port->ofproto->ofproto_class->set_rstp_port(port, NULL);
        }
        if (port->ofproto->ofproto_class->set_cfm) {
            port->ofproto->ofproto_class->set_cfm(port, NULL);
        }
        if (port->ofproto->ofproto_class->bundle_remove) {
            port->ofproto->ofproto_class->bundle_remove(port);
        }
    }
}

Project: ovs
File: ofproto.c

ofproto_reconnect_controllers(struct ofproto *ofproto)
{
    connmgr_reconnect(ofproto->connmgr);
}

Project: ovs
File: ofproto.c

ofproto_rule_unref(struct rule *rule)
{
    if (rule && ovs_refcount_unref_relaxed(&rule->ref_count) == 1) {
        ovs_assert(rule->state != RULE_INSERTED);
        ovsrcu_postpone(rule_destroy_cb, rule);
    }
}

Project: ovs
File: ofproto.c

ofproto_run(struct ofproto *p)
{
    int error;
    uint64_t new_seq;

    error = p->ofproto_class->run(p);
    if (error && error != EAGAIN) {
        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 rule *rule;

            if (!table->eviction) {
                continue;
            }

            if (table->n_flows > 100000) {
                static struct vlog_rate_limit count_rl =
                    VLOG_RATE_LIMIT_INIT(1, 1);
                VLOG_WARN_RL(&count_rl, "Table %"PRIuSIZE" has an excessive"
                             " number of rules: %d", i, table->n_flows);
            }

            ovs_mutex_lock(&ofproto_mutex);
            CLS_FOR_EACH (rule, cr, &table->cls) {
                if (rule->idle_timeout || rule->hard_timeout) {
                    if (!rule->eviction_group) {
                        eviction_group_add_rule(rule);
                    } else {
                        heap_raw_change(&rule->evg_node,
                                        rule_eviction_priority(p, rule));
                    }
                }
            }

            HEAP_FOR_EACH (evg, size_node, &table->eviction_groups_by_size) {
                heap_rebuild(&evg->rules);
            }
            ovs_mutex_unlock(&ofproto_mutex);
        }
    }

    if (p->ofproto_class->port_poll) {
        char *devname;

        while ((error = p->ofproto_class->port_poll(p, &devname)) != EAGAIN) {
            process_port_change(p, error, devname);
        }
    }

    new_seq = seq_read(connectivity_seq_get());
    if (new_seq != p->change_seq) {
        struct sset devnames;
        const char *devname;
        struct ofport *ofport;

        /* Update OpenFlow port status for any port whose netdev has changed.
         *
         * Refreshing a given 'ofport' can cause an arbitrary ofport to be
         * destroyed, so it's not safe to update ports directly from the
         * HMAP_FOR_EACH loop, or even to use HMAP_FOR_EACH_SAFE.  Instead, we
         * need this two-phase approach. */
        sset_init(&devnames);
        HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
            uint64_t port_change_seq;

            port_change_seq = netdev_get_change_seq(ofport->netdev);
            if (ofport->change_seq != port_change_seq) {
                ofport->change_seq = port_change_seq;
                sset_add(&devnames, netdev_get_name(ofport->netdev));
            }
        }
        SSET_FOR_EACH (devname, &devnames) {
            update_port(p, devname);
        }
        sset_destroy(&devnames);

        p->change_seq = new_seq;
    }

    connmgr_run(p->connmgr, handle_openflow);

    return error;
}

Project: ovs
File: ofproto.c

ofproto_set_aa(struct ofproto *ofproto, void *aux OVS_UNUSED,
               const struct aa_settings *s)
{
    if (!ofproto->ofproto_class->set_aa) {
        return EOPNOTSUPP;
    }
    ofproto->ofproto_class->set_aa(ofproto, s);
    return 0;
}

Project: ovs
File: ofproto.c

ofproto_set_controllers(struct ofproto *p,
                        const struct ofproto_controller *controllers,
                        size_t n_controllers, uint32_t allowed_versions)
{
    connmgr_set_controllers(p->connmgr, controllers, n_controllers,
                            allowed_versions);
}

Project: ovs
File: ofproto.c

ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id)
{
    uint64_t old_dpid = p->datapath_id;
    p->datapath_id = datapath_id ? datapath_id : pick_datapath_id(p);
    if (p->datapath_id != old_dpid) {
        /* Force all active connections to reconnect, since there is no way to
         * notify a controller that the datapath ID has changed. */
        ofproto_reconnect_controllers(p);
    }
}

Project: ovs
File: ofproto.c

ofproto_set_extra_in_band_remotes(struct ofproto *ofproto,
                                  const struct sockaddr_in *extras, size_t n)
{
    connmgr_set_extra_in_band_remotes(ofproto->connmgr, extras, n);
}

Project: ovs
File: ofproto.c

ofproto_set_fail_mode(struct ofproto *p, enum ofproto_fail_mode fail_mode)
{
    connmgr_set_fail_mode(p->connmgr, fail_mode);
}

Project: ovs
File: ofproto.c

ofproto_set_flood_vlans(struct ofproto *ofproto, unsigned long *flood_vlans)
{
    return (ofproto->ofproto_class->set_flood_vlans
            ? ofproto->ofproto_class->set_flood_vlans(ofproto, flood_vlans)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_set_flow_limit(unsigned limit)
{
    ofproto_flow_limit = limit;
}

Project: ovs
File: ofproto.c

ofproto_set_flow_restore_wait(bool flow_restore_wait_db)
{
    flow_restore_wait = flow_restore_wait_db;
}

Project: ovs
File: ofproto.c

ofproto_set_forward_bpdu(struct ofproto *ofproto, bool forward_bpdu)
{
    bool old_val = ofproto->forward_bpdu;
    ofproto->forward_bpdu = forward_bpdu;
    if (old_val != ofproto->forward_bpdu) {
        if (ofproto->ofproto_class->forward_bpdu_changed) {
            ofproto->ofproto_class->forward_bpdu_changed(ofproto);
        }
    }
}

Project: ovs
File: ofproto.c

ofproto_set_in_band_queue(struct ofproto *ofproto, int queue_id)
{
    connmgr_set_in_band_queue(ofproto->connmgr, queue_id);
}

Project: ovs
File: ofproto.c

ofproto_set_ipfix(struct ofproto *ofproto,
                  const struct ofproto_ipfix_bridge_exporter_options *bo,
                  const struct ofproto_ipfix_flow_exporter_options *fo,
                  size_t n_fo)
{
    if (ofproto->ofproto_class->set_ipfix) {
        return ofproto->ofproto_class->set_ipfix(ofproto, bo, fo, n_fo);
    } else {
        return (bo || fo) ? EOPNOTSUPP : 0;
    }
}

Project: ovs
File: ofproto.c

ofproto_set_max_idle(unsigned max_idle)
{
    ofproto_max_idle = max_idle;
}

Project: ovs
File: ofproto.c

ofproto_set_mcast_snooping(struct ofproto *ofproto,
                           const struct ofproto_mcast_snooping_settings *s)
{
    return (ofproto->ofproto_class->set_mcast_snooping
            ? ofproto->ofproto_class->set_mcast_snooping(ofproto, s)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_set_netflow(struct ofproto *ofproto,
                    const struct netflow_options *nf_options)
{
    if (nf_options && sset_is_empty(&nf_options->collectors)) {
        nf_options = NULL;
    }

    if (ofproto->ofproto_class->set_netflow) {
        return ofproto->ofproto_class->set_netflow(ofproto, nf_options);
    } else {
        return nf_options ? EOPNOTSUPP : 0;
    }
}

Project: ovs
File: ofproto.c

ofproto_set_rstp(struct ofproto *ofproto,
                 const struct ofproto_rstp_settings *s)
{
    if (!ofproto->ofproto_class->set_rstp) {
        return EOPNOTSUPP;
    }
    ofproto->ofproto_class->set_rstp(ofproto, s);
    return 0;
}

Project: ovs
File: ofproto.c

ofproto_set_sflow(struct ofproto *ofproto,
                  const struct ofproto_sflow_options *oso)
{
    if (oso && sset_is_empty(&oso->targets)) {
        oso = NULL;
    }

    if (ofproto->ofproto_class->set_sflow) {
        return ofproto->ofproto_class->set_sflow(ofproto, oso);
    } else {
        return oso ? EOPNOTSUPP : 0;
    }
}

Project: ovs
File: ofproto.c

ofproto_set_snoops(struct ofproto *ofproto, const struct sset *snoops)
{
    return connmgr_set_snoops(ofproto->connmgr, snoops);
}

Project: ovs
File: ofproto.c

ofproto_set_stp(struct ofproto *ofproto,
                const struct ofproto_stp_settings *s)
{
    return (ofproto->ofproto_class->set_stp
            ? ofproto->ofproto_class->set_stp(ofproto, s)
            : EOPNOTSUPP);
}

Project: ovs
File: ofproto.c

ofproto_set_threads(int n_handlers_, int n_revalidators_)
{
    int threads = MAX(count_cpu_cores(), 2);

    n_revalidators = MAX(n_revalidators_, 0);
    n_handlers = MAX(n_handlers_, 0);

    if (!n_revalidators) {
        n_revalidators = n_handlers
            ? MAX(threads - (int) n_handlers, 1)
            : threads / 4 + 1;
    }

    if (!n_handlers) {
        n_handlers = MAX(threads - (int) n_revalidators, 1);
    }
}

Project: ovs
File: ofproto.c

ofproto_table_get_miss_config(const struct ofproto *ofproto, uint8_t table_id)
{
    enum ofputil_table_miss miss;

    atomic_read_relaxed(&ofproto->tables[table_id].miss_config, &miss);
    return miss;
}

Project: ovs
File: ofproto.c

ofproto_type_get_memory_usage(const char *datapath_type, struct simap *usage)
{
    const struct ofproto_class *class;

    datapath_type = ofproto_normalize_type(datapath_type);
    class = ofproto_class_find__(datapath_type);

    if (class && class->type_get_memory_usage) {
        class->type_get_memory_usage(datapath_type, usage);
    }
}

Project: ovs
File: ofproto.c

ofproto_type_run(const char *datapath_type)
{
    const struct ofproto_class *class;
    int error;

    datapath_type = ofproto_normalize_type(datapath_type);
    class = ofproto_class_find__(datapath_type);

    error = class->type_run ? class->type_run(datapath_type) : 0;
    if (error && error != EAGAIN) {
        VLOG_ERR_RL(&rl, "%s: type_run failed (%s)",
                    datapath_type, ovs_strerror(error));
    }
    return error;
}

Project: ovs
File: ofproto.c

ofproto_unixctl_init(void)
{
    static bool registered;
    if (registered) {
        return;
    }
    registered = true;

    unixctl_command_register("ofproto/list", "", 0, 0,
                             ofproto_unixctl_list, NULL);
}

Project: ovs
File: ofproto.c

ofproto_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
                     const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
{
    struct ofproto *ofproto;
    struct ds results;

    ds_init(&results);
    HMAP_FOR_EACH (ofproto, hmap_node, &all_ofprotos) {
        ds_put_format(&results, "%s\n", ofproto->name);
    }
    unixctl_command_reply(conn, ds_cstr(&results));
    ds_destroy(&results);
}

Project: ovs
File: ofproto.c

ofproto_wait(struct ofproto *p)
{
    p->ofproto_class->wait(p);
    if (p->ofproto_class->port_poll_wait) {
        p->ofproto_class->port_poll_wait(p);
    }
    seq_wait(connectivity_seq_get(), p->change_seq);
    connmgr_wait(p->connmgr);
}

Project: ovs
File: ofproto.c

oftable_destroy(struct oftable *table)
{
    ovs_assert(classifier_is_empty(&table->cls));

    ovs_mutex_lock(&ofproto_mutex);
    oftable_configure_eviction(table, 0, NULL, 0);
    ovs_mutex_unlock(&ofproto_mutex);

    hmap_destroy(&table->eviction_groups_by_id);
    heap_destroy(&table->eviction_groups_by_size);
    classifier_destroy(&table->cls);
    free(table->name);
}

Project: ovs
File: ofproto.c

oftable_init(struct oftable *table)
{
    memset(table, 0, sizeof *table);
    classifier_init(&table->cls, flow_segment_u64s);
    table->max_flows = UINT_MAX;
    table->n_flows = 0;
    hmap_init(&table->eviction_groups_by_id);
    heap_init(&table->eviction_groups_by_size);
    atomic_init(&table->miss_config, OFPUTIL_TABLE_MISS_DEFAULT);

    classifier_set_prefix_fields(&table->cls, default_prefix_fields,
                                 ARRAY_SIZE(default_prefix_fields));

    atomic_init(&table->n_matched, 0);
    atomic_init(&table->n_missed, 0);
}

Project: ovs
File: ofproto.c

oftable_set_name(struct oftable *table, const char *name)
{
    if (name && name[0]) {
        int len = strnlen(name, OFP_MAX_TABLE_NAME_LEN);
        if (!table->name || strncmp(name, table->name, len)) {
            free(table->name);
            table->name = xmemdup0(name, len);
        }
    } else {
        free(table->name);
        table->name = NULL;
    }
}

Project: ovs
File: ofproto.c

oftable_vacancy(const struct oftable *t)
{
    return (!t->max_flows ? 100
            : t->n_flows >= t->max_flows ? 0
            : (t->max_flows - t->n_flows) * 100.0 / t->max_flows);
}

Project: ovs
File: ofproto.c

pick_fallback_dpid(void)
{
    struct eth_addr ea;
    eth_addr_nicira_random(&ea);
    return eth_addr_to_uint64(ea);
}

Project: ovs
File: ofproto.c

port_mod_finish(struct ofconn *ofconn, struct ofputil_port_mod *pm,
                struct ofport *port)
{
    update_port_config(ofconn, port, pm->config, pm->mask);
    if (pm->advertise) {
        netdev_set_advertisements(port->netdev, pm->advertise);
    }
}

Project: ovs
File: ofproto.c

port_mod_start(struct ofconn *ofconn, struct ofputil_port_mod *pm,
               struct ofport **port)
{
    struct ofproto *p = ofconn_get_ofproto(ofconn);

    *port = ofproto_get_port(p, pm->port_no);
    if (!*port) {
        return OFPERR_OFPPMFC_BAD_PORT;
    }
    if (!eth_addr_equals((*port)->pp.hw_addr, pm->hw_addr)) {
        return OFPERR_OFPPMFC_BAD_HW_ADDR;
    }
    return 0;
}

Project: ovs
File: ofproto.c

process_port_change(struct ofproto *ofproto, int error, char *devname)
{
    if (error == ENOBUFS) {
        reinit_ports(ofproto);
    } else if (!error) {
        update_port(ofproto, devname);
        free(devname);
    }
}

Project: ovs
File: ofproto.c

put_queue_get_config_reply(struct ofport *port, uint32_t queue,
                           struct ovs_list *replies)
{
    struct ofputil_queue_config qc;

    /* None of the existing queues have compatible properties, so we hard-code
     * omitting min_rate and max_rate. */
    qc.port = port->ofp_port;
    qc.queue = queue;
    qc.min_rate = UINT16_MAX;
    qc.max_rate = UINT16_MAX;
    ofputil_append_queue_get_config_reply(&qc, replies);
}

Project: ovs
File: ofproto.c

put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
                const struct netdev_queue_stats *stats)
{
    struct ofputil_queue_stats oqs;

    oqs.port_no = cbdata->ofport->pp.port_no;
    oqs.queue_id = queue_id;
    oqs.tx_bytes = stats->tx_bytes;
    oqs.tx_packets = stats->tx_packets;
    oqs.tx_errors = stats->tx_errors;
    if (stats->created != LLONG_MIN) {
        calc_duration(stats->created, cbdata->now,
                      &oqs.duration_sec, &oqs.duration_nsec);
    } else {
        oqs.duration_sec = oqs.duration_nsec = UINT32_MAX;
    }
    ofputil_append_queue_stat(&cbdata->replies, &oqs);
}

Project: ovs
File: ofproto.c

query_switch_features(struct ofproto *ofproto,
                      bool *arp_match_ip, uint64_t *ofpacts)
{
    struct ofputil_table_features *features, *f;

    *arp_match_ip = false;
    *ofpacts = 0;

    query_tables(ofproto, &features, NULL);
    for (f = features; f < &features[ofproto->n_tables]; f++) {
        *ofpacts |= f->nonmiss.apply.ofpacts | f->miss.apply.ofpacts;
        if (bitmap_is_set(f->match.bm, MFF_ARP_SPA) ||
            bitmap_is_set(f->match.bm, MFF_ARP_TPA)) {
            *arp_match_ip = true;
        }
    }
    free(features);

    /* Sanity check. */
    ovs_assert(*ofpacts & (UINT64_C(1) << OFPACT_OUTPUT));
}

Project: ovs
File: ofproto.c

query_tables(struct ofproto *ofproto,
             struct ofputil_table_features **featuresp,
             struct ofputil_table_stats **statsp)
{
    struct mf_bitmap rw_fields = oxm_writable_fields();
    struct mf_bitmap match = oxm_matchable_fields();
    struct mf_bitmap mask = oxm_maskable_fields();

    struct ofputil_table_features *features;
    struct ofputil_table_stats *stats;
    int i;

    features = *featuresp = xcalloc(ofproto->n_tables, sizeof *features);
    for (i = 0; i < ofproto->n_tables; i++) {
        struct ofputil_table_features *f = &features[i];

        f->table_id = i;
        sprintf(f->name, "table%d", i);
        f->metadata_match = OVS_BE64_MAX;
        f->metadata_write = OVS_BE64_MAX;
        atomic_read_relaxed(&ofproto->tables[i].miss_config, &f->miss_config);
        f->max_entries = 1000000;

        bool more_tables = false;
        for (int j = i + 1; j < ofproto->n_tables; j++) {
            if (!(ofproto->tables[j].flags & OFTABLE_HIDDEN)) {
                bitmap_set1(f->nonmiss.next, j);
                more_tables = true;
            }
        }
        f->nonmiss.instructions = (1u << N_OVS_INSTRUCTIONS) - 1;
        if (!more_tables) {
            f->nonmiss.instructions &= ~(1u << OVSINST_OFPIT11_GOTO_TABLE);
        }
        f->nonmiss.write.ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
        f->nonmiss.write.set_fields = rw_fields;
        f->nonmiss.apply = f->nonmiss.write;
        f->miss = f->nonmiss;

        f->match = match;
        f->mask = mask;
        f->wildcard = match;
    }

    if (statsp) {
        stats = *statsp = xcalloc(ofproto->n_tables, sizeof *stats);
        for (i = 0; i < ofproto->n_tables; i++) {
            struct ofputil_table_stats *s = &stats[i];

            s->table_id = i;
            s->active_count = ofproto->tables[i].n_flows;
            if (i == 0) {
                s->active_count -= connmgr_count_hidden_rules(
                    ofproto->connmgr);
            }
        }
    } else {
        stats = NULL;
    }

    ofproto->ofproto_class->query_tables(ofproto, features, stats);

    for (i = 0; i < ofproto->n_tables; i++) {
        const struct oftable *table = &ofproto->tables[i];
        struct ofputil_table_features *f = &features[i];

        if (table->name) {
            ovs_strzcpy(f->name, table->name, sizeof f->name);
        }

        if (table->max_flows < f->max_entries) {
            f->max_entries = table->max_flows;
        }
    }
}

Project: ovs
File: ofproto.c

query_tables_desc(struct ofproto *ofproto, struct ofputil_table_desc **descp)
{
    struct ofputil_table_desc *table_desc;
    size_t i;

    table_desc = *descp = xcalloc(ofproto->n_tables, sizeof *table_desc);
    for (i = 0; i < ofproto->n_tables; i++) {
        struct ofputil_table_desc *td = &table_desc[i];
        query_table_desc__(td, ofproto, i);
    }
}

Project: ovs
File: ofproto.c

reduce_timeout(uint16_t max, uint16_t *timeout)
{
    if (max && (!*timeout || *timeout > max)) {
        *timeout = max;
    }
}

Project: ovs
File: ofproto.c

reinit_ports(struct ofproto *p)
{
    struct ofproto_port_dump dump;
    struct sset devnames;
    struct ofport *ofport;
    struct ofproto_port ofproto_port;
    const char *devname;

    COVERAGE_INC(ofproto_reinit_ports);

    sset_init(&devnames);
    HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
        sset_add(&devnames, netdev_get_name(ofport->netdev));
    }
    OFPROTO_PORT_FOR_EACH (&ofproto_port, &dump, p) {
        sset_add(&devnames, ofproto_port.name);
    }

    SSET_FOR_EACH (devname, &devnames) {
        update_port(p, devname);
    }
    sset_destroy(&devnames);
}

Project: ovs
File: ofproto.c

reject_slave_controller(struct ofconn *ofconn)
{
    if (ofconn_get_type(ofconn) == OFCONN_PRIMARY
        && ofconn_get_role(ofconn) == OFPCR12_ROLE_SLAVE) {
        return OFPERR_OFPBRC_IS_SLAVE;
    } else {
        return 0;
    }
}

Project: ovs
File: ofproto.c

replace_rule_revert(struct ofproto *ofproto,
                    struct rule *old_rule, struct rule *new_rule)
{
    struct oftable *table = &ofproto->tables[new_rule->table_id];

    if (old_rule) {
        if (old_rule->removed_reason == OFPRR_EVICTION) {
            /* Revert the eviction. */
            eviction_group_add_rule(old_rule);
        }

        /* Restore the old rule to data structures. */
        ofproto_rule_insert__(ofproto, old_rule);

        /* Restore the original visibility of the old rule. */
        cls_rule_restore_visibility(&old_rule->cr);
    } else {
        /* Restore table's rule count. */
        table->n_flows--;
    }

    /* Remove the new rule immediately.  It was never visible to lookups. */
    if (!classifier_remove(&table->cls, &new_rule->cr)) {
        OVS_NOT_REACHED();
    }
    ofproto_rule_remove__(ofproto, new_rule);
    ofproto_rule_unref(new_rule);
}

Project: ovs
File: ofproto.c

rule_actions_create(const struct ofpact *ofpacts, size_t ofpacts_len)
{
    struct rule_actions *actions;

    actions = xmalloc(sizeof *actions + ofpacts_len);
    actions->ofpacts_len = ofpacts_len;
    memcpy(actions->ofpacts, ofpacts, ofpacts_len);
    actions->has_meter = ofpacts_get_meter(ofpacts, ofpacts_len) != 0;
    actions->has_groups =
        (ofpact_find_type_flattened(ofpacts, OFPACT_GROUP,
                                    ofpact_end(ofpacts, ofpacts_len))
         != NULL);
    actions->has_learn_with_delete = (next_learn_with_delete(actions, NULL)
                                      != NULL);

    return actions;
}

Project: ovs
File: ofproto.c

rule_actions_destroy(const struct rule_actions *actions)
{
    if (actions) {
        ovsrcu_postpone(free, CONST_CAST(struct rule_actions *, actions));
    }
}

Project: ovs
File: ofproto.c

rule_criteria_destroy(struct rule_criteria *criteria)
{
    cls_rule_destroy(&criteria->cr);
    criteria->version = OVS_VERSION_NOT_REMOVED; /* Mark as destroyed. */
}

Project: ovs
File: ofproto.c

rule_criteria_init(struct rule_criteria *criteria, uint8_t table_id,
                   const struct match *match, int priority,
                   ovs_version_t version, ovs_be64 cookie,
                   ovs_be64 cookie_mask, ofp_port_t out_port,
                   uint32_t out_group)
{
    criteria->table_id = table_id;
    cls_rule_init(&criteria->cr, match, priority);
    criteria->version = version;
    criteria->cookie = cookie;
    criteria->cookie_mask = cookie_mask;
    criteria->out_port = out_port;
    criteria->out_group = out_group;

    /* We ordinarily want to skip hidden rules, but there has to be a way for
     * code internal to OVS to modify and delete them, so if the criteria
     * specify a priority that can only be for a hidden flow, then allow hidden
     * rules to be selected.  (This doesn't allow OpenFlow clients to meddle
     * with hidden flows because OpenFlow uses only a 16-bit field to specify
     * priority.) */
    criteria->include_hidden = priority > UINT16_MAX;

    /* We assume that the criteria are being used to collect flows for reading
     * but not modification.  Thus, we should collect read-only flows. */
    criteria->include_readonly = true;
}

Project: ovs
File: ofproto.c

rule_criteria_require_rw(struct rule_criteria *criteria,
                         bool can_write_readonly)
{
    criteria->include_readonly = can_write_readonly;
}

Project: ovs
File: ofproto.c

rule_is_readonly(const struct rule *rule)
{
    const struct oftable *table = &rule->ofproto->tables[rule->table_id];
    return (table->flags & OFTABLE_READONLY) != 0;
}

Project: ovs
File: ofproto.c

send_table_status(struct ofproto *ofproto, uint8_t table_id)
{
    struct oftable *t = &ofproto->tables[table_id];
    if (!t->vacancy_event) {
        return;
    }

    uint8_t vacancy = oftable_vacancy(t);
    enum ofp14_table_reason event;
    if (vacancy < t->vacancy_down) {
        event = OFPTR_VACANCY_DOWN;
    } else if (vacancy > t->vacancy_up) {
        event = OFPTR_VACANCY_UP;
    } else {
        return;
    }

    if (event == t->vacancy_event) {
        struct ofputil_table_desc td;
        query_table_desc__(&td, ofproto, table_id);
        connmgr_send_table_status(ofproto->connmgr, &td, event);

        t->vacancy_event = (event == OFPTR_VACANCY_DOWN
                            ? OFPTR_VACANCY_UP
                            : OFPTR_VACANCY_DOWN);
    }
}

Project: ovs
File: ofproto.c

simple_flow_mod(struct ofproto *ofproto,
                const struct match *match, int priority,
                const struct ofpact *ofpacts, size_t ofpacts_len,
                enum ofp_flow_mod_command command)
{
    struct ofputil_flow_mod fm;

    flow_mod_init(&fm, match, priority, ofpacts, ofpacts_len, command);

    return handle_flow_mod__(ofproto, &fm, NULL);
}

Project: ovs
File: ofproto.c

table_mod(struct ofproto *ofproto, const struct ofputil_table_mod *tm)
{
    if (!check_table_id(ofproto, tm->table_id)) {
        return OFPERR_OFPTMFC_BAD_TABLE;
    }

    /* Don't allow the eviction flags to be changed (except to the only fixed
     * value that OVS supports).  OF1.4 says this is normal: "The
     * OFPTMPT_EVICTION property usually cannot be modified using a
     * OFP_TABLE_MOD request, because the eviction mechanism is switch
     * defined". */
    if (tm->eviction_flags != UINT32_MAX
        && tm->eviction_flags != OFPROTO_EVICTION_FLAGS) {
        return OFPERR_OFPTMFC_BAD_CONFIG;
    }

    if (tm->table_id == OFPTT_ALL) {
        struct oftable *oftable;
        OFPROTO_FOR_EACH_TABLE (oftable, ofproto) {
            if (!(oftable->flags & (OFTABLE_HIDDEN | OFTABLE_READONLY))) {
                table_mod__(oftable, tm);
            }
        }
    } else {
        struct oftable *oftable = &ofproto->tables[tm->table_id];
        if (oftable->flags & OFTABLE_READONLY) {
            return OFPERR_OFPTMFC_EPERM;
        }
        table_mod__(oftable, tm);
    }

    return 0;
}

Project: ovs
File: ofproto.c

table_mod__(struct oftable *oftable,
            const struct ofputil_table_mod *tm)
{
    if (tm->miss == OFPUTIL_TABLE_MISS_DEFAULT) {
        /* This is how an OFPT_TABLE_MOD decodes if it doesn't specify any
         * table-miss configuration (because the protocol used doesn't have
         * such a concept), so there's nothing to do. */
    } else {
        atomic_store_relaxed(&oftable->miss_config, tm->miss);
    }

    unsigned int new_eviction = oftable->eviction;
    if (tm->eviction == OFPUTIL_TABLE_EVICTION_ON) {
        new_eviction |= EVICTION_OPENFLOW;
    } else if (tm->eviction == OFPUTIL_TABLE_EVICTION_OFF) {
        new_eviction &= ~EVICTION_OPENFLOW;
    }

    if (new_eviction != oftable->eviction) {
        ovs_mutex_lock(&ofproto_mutex);
        oftable_configure_eviction(oftable, new_eviction,
                                   oftable->eviction_fields,
                                   oftable->n_eviction_fields);
        ovs_mutex_unlock(&ofproto_mutex);
    }

    if (tm->vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
        ovs_mutex_lock(&ofproto_mutex);
        oftable->vacancy_down = tm->table_vacancy.vacancy_down;
        oftable->vacancy_up = tm->table_vacancy.vacancy_up;
        if (tm->vacancy == OFPUTIL_TABLE_VACANCY_OFF) {
            oftable->vacancy_event = 0;
        } else if (!oftable->vacancy_event) {
            uint8_t vacancy = oftable_vacancy(oftable);
            oftable->vacancy_event = (vacancy < oftable->vacancy_up
                                      ? OFPTR_VACANCY_UP
                                      : OFPTR_VACANCY_DOWN);
        }
        ovs_mutex_unlock(&ofproto_mutex);
    }
}

Project: ovs
File: ofproto.c

update_mtu(struct ofproto *p, struct ofport *port)
{
    struct netdev *netdev = port->netdev;
    int dev_mtu;

    if (netdev_get_mtu(netdev, &dev_mtu)) {
        port->mtu = 0;
        return;
    }
    if (ofport_is_mtu_overridden(p, port)) {
        if (dev_mtu > p->min_mtu) {
            if (!netdev_set_mtu(port->netdev, p->min_mtu)) {
                dev_mtu = p->min_mtu;
            }
        }
        port->mtu = dev_mtu;
        return;
    }

    port->mtu = dev_mtu;
    /* For non-overridden port find new min mtu. */

    update_mtu_ofproto(p);
}

Project: ovs
File: ofproto.c

update_mtu_ofproto(struct ofproto *p)
{
    struct ofport *ofport;
    int old_min = p->min_mtu;

    p->min_mtu = find_min_mtu(p);
    if (p->min_mtu == old_min) {
        return;
    }

    HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
        struct netdev *netdev = ofport->netdev;

        if (ofport_is_mtu_overridden(p, ofport)) {
            if (!netdev_set_mtu(netdev, p->min_mtu)) {
                ofport->mtu = p->min_mtu;
            }
        }
    }
}

Project: ovs
File: ofproto.c

update_port(struct ofproto *ofproto, const char *name)
{
    struct ofproto_port ofproto_port;
    struct ofputil_phy_port pp;
    struct netdev *netdev;
    struct ofport *port;
    int error = 0;

    COVERAGE_INC(ofproto_update_port);

    /* Fetch 'name''s location and properties from the datapath. */
    netdev = (!ofproto_port_query_by_name(ofproto, name, &ofproto_port)
              ? ofport_open(ofproto, &ofproto_port, &pp)
              : NULL);

    if (netdev) {
        port = ofproto_get_port(ofproto, ofproto_port.ofp_port);
        if (port && !strcmp(netdev_get_name(port->netdev), name)) {
            struct netdev *old_netdev = port->netdev;

            /* 'name' hasn't changed location.  Any properties changed? */
            if (!ofport_equal(&port->pp, &pp)) {
                ofport_modified(port, &pp);
            }

            update_mtu(ofproto, port);

            /* Install the newly opened netdev in case it has changed.
             * Don't close the old netdev yet in case port_modified has to
             * remove a retained reference to it.*/
            port->netdev = netdev;
            port->change_seq = netdev_get_change_seq(netdev);

            if (port->ofproto->ofproto_class->port_modified) {
                port->ofproto->ofproto_class->port_modified(port);
            }

            netdev_close(old_netdev);
        } else {
            /* If 'port' is nonnull then its name differs from 'name' and thus
             * we should delete it.  If we think there's a port named 'name'
             * then its port number must be wrong now so delete it too. */
            if (port) {
                ofport_remove(port);
            }
            ofport_remove_with_name(ofproto, name);
            error = ofport_install(ofproto, netdev, &pp);
        }
    } else {
        /* Any port named 'name' is gone now. */
        ofport_remove_with_name(ofproto, name);
    }
    ofproto_port_destroy(&ofproto_port);

    return error;
}

Project: ovs
File: ofproto.c

update_port_config(struct ofconn *ofconn, struct ofport *port,
                   enum ofputil_port_config config,
                   enum ofputil_port_config mask)
{
    enum ofputil_port_config toggle = (config ^ port->pp.config) & mask;

    if (toggle & OFPUTIL_PC_PORT_DOWN
        && (config & OFPUTIL_PC_PORT_DOWN
            ? netdev_turn_flags_off(port->netdev, NETDEV_UP, NULL)
            : netdev_turn_flags_on(port->netdev, NETDEV_UP, NULL))) {
        /* We tried to bring the port up or down, but it failed, so don't
         * update the "down" bit. */
        toggle &= ~OFPUTIL_PC_PORT_DOWN;
    }

    if (toggle) {
        enum ofputil_port_config old_config = port->pp.config;
        port->pp.config ^= toggle;
        port->ofproto->ofproto_class->port_reconfigured(port, old_config);
        connmgr_send_port_status(port->ofproto->connmgr, ofconn, &port->pp,
                                 OFPPR_MODIFY);
    }
}