openflow流表超时时间

插入openflow流表时,如果超时时间不为0,则将rule插入超时链表

ofproto_rule_insert__
    const struct rule_actions *actions = rule_get_actions(rule);
    if (rule->hard_timeout || rule->idle_timeout) {
        ovs_list_insert(&ofproto->expirable, &rule->expirable);
    }

在ovs-vswitchd主循环中,每次遍历超时链表,将超时的rule删除

run
        LIST_FOR_EACH_SAFE (rule, next_rule, expirable,
                            &ofproto->up.expirable) {
            rule_expire(rule_dpif_cast(rule), now);
        }


/* If 'rule' is an OpenFlow rule, that has expired according to OpenFlow rules,
 * then delete it entirely. */
static void
rule_expire(struct rule_dpif *rule, long long now)
    OVS_REQUIRES(ofproto_mutex)
{
    uint16_t hard_timeout, idle_timeout;
    int reason = -1;

    hard_timeout = rule->up.hard_timeout;
    idle_timeout = rule->up.idle_timeout;

    //如果指定了hard_timeout,则不管此rule有没有数据,超时后也会被删除
    /* Has 'rule' expired? */
    if (hard_timeout) {
        long long int modified;

        ovs_mutex_lock(&rule->up.mutex);
        modified = rule->up.modified;
        ovs_mutex_unlock(&rule->up.mutex);

        if (now > modified + hard_timeout * 1000) {
            reason = OFPRR_HARD_TIMEOUT;
        }
    }

    //如果指定了 idle_timeout,则从rule上次被使用到现在的时间计算超时时间
    if (reason < 0 && idle_timeout) {
        long long int used;

        ovs_mutex_lock(&rule->stats_mutex);
        used = rule->stats.used;
        ovs_mutex_unlock(&rule->stats_mutex);

        if (now > used + idle_timeout * 1000) {
            reason = OFPRR_IDLE_TIMEOUT;
        }
    }

    if (reason >= 0) {
        COVERAGE_INC(ofproto_dpif_expired);
        ofproto_rule_expire(&rule->up, reason);
    }
}

void
ofproto_rule_expire(struct rule *rule, uint8_t reason)
    OVS_REQUIRES(ofproto_mutex)
{
    struct rule_collection rules;

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

hard_timeout的rule超时后可以直接删除,但是idle_timeout的rule需要等到rule上没有流量经过后,等指定时间后才会被删除。

idle_timeout的rule的更新时间在revalidate线程的revalidate_ukey函数执行,如下所示

revalidate
    for (;;) {
        //先去datapath获取流表
        n_dumped = dpif_flow_dump_next(dump_thread, flows, ARRAY_SIZE(flows));
        //获取不到说明已经全部获取了,跳出循环
        if (!n_dumped) {
            break;
        }

        for (f = flows; f < &flows[n_dumped]; f++) {
            if (kill_them_all || (used && used < now - max_idle)) {
                result = UKEY_DELETE;
            } else {
                //只有还存在datapath的流表,并且没有超时被删除的流表,才会更新其对应的openflow流表
                result = revalidate_ukey(udpif, ukey, &f->stats, &odp_actions, reval_seq, &recircs);
                    //调用xlate_ukey时,在 cache 里添加 XC_RULE
                    if (need_revalidate) {
                        if (should_revalidate(udpif, push.n_packets, ukey->stats.used)) {
                            if (!ukey->xcache) {
                                ukey->xcache = xlate_cache_new();
                            } else {
                                xlate_cache_clear(ukey->xcache);
                            }
                            result = revalidate_ukey__(udpif, ukey, push.tcp_flags, odp_actions, recircs, ukey->xcache);
                        } /* else delete; too expensive to revalidate */
                    } else if (!push.n_packets || ukey->xcache
                               || !populate_xcache(udpif, ukey, push.tcp_flags)) {
                        result = UKEY_KEEP;
                    }

                    /* Stats for deleted flows will be attributed upon flow deletion. Skip. */
                    if (result != UKEY_DELETE) {
                        xlate_push_stats(ukey->xcache, &push);
                        ukey->stats = *stats;
                        ukey->reval_seq = reval_seq;
                    }
            }
        }
    }

#revalidate_ukey__ 和 populate_xcache 都会调用 xlate_ukey,最终添加 XC_RULE
xlate_ukey(udpif, ukey, tcp_flags, &ctx);
    xlate_key(udpif, ukey->key, ukey->key_len, &push, ctx);
        xlate_actions(&xin, &ctx->xout);
            if (!xin->ofpacts && !ctx.rule) {
                ctx.rule = rule_dpif_lookup_from_table(
                    ctx.xbridge->ofproto, ctx.xin->tables_version, flow, ctx.wc,
                    ctx.xin->resubmit_stats, &ctx.table_id,
                    flow->in_port.ofp_port, true, true, ctx.xin->xcache);

                if (ctx.xin->xcache) {
                    struct xc_entry *entry;

                    entry = xlate_cache_add_entry(ctx.xin->xcache, XC_RULE);
                    entry->rule = ctx.rule;
                    ofproto_rule_ref(&ctx.rule->up);
                }
            }

void
xlate_push_stats(struct xlate_cache *xcache,
                 struct dpif_flow_stats *stats)
{
    if (!stats->n_packets) {
        return;
    }

    struct xc_entry *entry;
    struct ofpbuf entries = xcache->entries;
    XC_ENTRY_FOR_EACH (entry, &entries) {
        xlate_push_stats_entry(entry, stats);
    }
}

/* Push stats and perform side effects of flow translation. */
void
xlate_push_stats_entry(struct xc_entry *entry,
                       struct dpif_flow_stats *stats)
    switch (entry->type) {
    ...
    case XC_RULE:
        rule_dpif_credit_stats(entry->rule, stats);
        break;
    ...
    }
}

void
rule_dpif_credit_stats(struct rule_dpif *rule,
                       const struct dpif_flow_stats *stats)
{
    ovs_mutex_lock(&rule->stats_mutex);
    if (OVS_UNLIKELY(rule->new_rule)) {
        ovs_mutex_lock(&rule->new_rule->stats_mutex);
        rule_dpif_credit_stats__(rule->new_rule, stats, rule->forward_counts);
        ovs_mutex_unlock(&rule->new_rule->stats_mutex);
    } else {
        rule_dpif_credit_stats__(rule, stats, true);
    }
    ovs_mutex_unlock(&rule->stats_mutex);
}

static void
rule_dpif_credit_stats__(struct rule_dpif *rule,
                         const struct dpif_flow_stats *stats,
                         bool credit_counts)
    OVS_REQUIRES(rule->stats_mutex)
{
    if (credit_counts) {
        rule->stats.n_packets += stats->n_packets;
        rule->stats.n_bytes += stats->n_bytes;
    }

    //更新流表时间
    rule->stats.used = MAX(rule->stats.used, stats->used);
}

你可能感兴趣的:(openflow流表超时时间)