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);
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 193,968评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,682评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,254评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,074评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,964评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,055评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,484评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,170评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,433评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,512评论 2 308
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,296评论 1 325
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,184评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,545评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,150评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,437评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,630评论 2 335

推荐阅读更多精彩内容