Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 187973
b: refs/heads/master
c: 9837638
h: refs/heads/master
i:
  187971: 76515d9
v: v3
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Mar 8, 2010
1 parent 2e002ff commit 13948f8
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 13 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1515faf2f995add976d4428bbc1583a4a0c81e5f
refs/heads/master: 9837638727488922727b0cfd438039fa73364183
50 changes: 38 additions & 12 deletions trunk/net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
static void ipv4_link_failure(struct sk_buff *skb);
static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
static int rt_garbage_collect(struct dst_ops *ops);
static void rt_emergency_hash_rebuild(struct net *net);


static struct dst_ops ipv4_dst_ops = {
Expand Down Expand Up @@ -780,11 +779,30 @@ static void rt_do_flush(int process_context)
#define FRACT_BITS 3
#define ONE (1UL << FRACT_BITS)

/*
* Given a hash chain and an item in this hash chain,
* find if a previous entry has the same hash_inputs
* (but differs on tos, mark or oif)
* Returns 0 if an alias is found.
* Returns ONE if rth has no alias before itself.
*/
static int has_noalias(const struct rtable *head, const struct rtable *rth)
{
const struct rtable *aux = head;

while (aux != rth) {
if (compare_hash_inputs(&aux->fl, &rth->fl))
return 0;
aux = aux->u.dst.rt_next;
}
return ONE;
}

static void rt_check_expire(void)
{
static unsigned int rover;
unsigned int i = rover, goal;
struct rtable *rth, *aux, **rthp;
struct rtable *rth, **rthp;
unsigned long samples = 0;
unsigned long sum = 0, sum2 = 0;
unsigned long delta;
Expand Down Expand Up @@ -835,15 +853,7 @@ static void rt_check_expire(void)
* attributes don't unfairly skew
* the length computation
*/
for (aux = rt_hash_table[i].chain;;) {
if (aux == rth) {
length += ONE;
break;
}
if (compare_hash_inputs(&aux->fl, &rth->fl))
break;
aux = aux->u.dst.rt_next;
}
length += has_noalias(rt_hash_table[i].chain, rth);
continue;
}
} else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout))
Expand Down Expand Up @@ -1073,6 +1083,21 @@ static int rt_garbage_collect(struct dst_ops *ops)
out: return 0;
}

/*
* Returns number of entries in a hash chain that have different hash_inputs
*/
static int slow_chain_length(const struct rtable *head)
{
int length = 0;
const struct rtable *rth = head;

while (rth) {
length += has_noalias(head, rth);
rth = rth->u.dst.rt_next;
}
return length >> FRACT_BITS;
}

static int rt_intern_hash(unsigned hash, struct rtable *rt,
struct rtable **rp, struct sk_buff *skb)
{
Expand Down Expand Up @@ -1185,7 +1210,8 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt,
rt_free(cand);
}
} else {
if (chain_length > rt_chain_length_max) {
if (chain_length > rt_chain_length_max &&
slow_chain_length(rt_hash_table[hash].chain) > rt_chain_length_max) {
struct net *net = dev_net(rt->u.dst.dev);
int num = ++net->ipv4.current_rt_cache_rebuild_count;
if (!rt_caching(dev_net(rt->u.dst.dev))) {
Expand Down

0 comments on commit 13948f8

Please sign in to comment.