插入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);
}