diff options
author | David S. Miller <davem@davemloft.net> | 2011-02-04 18:55:25 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-04 18:59:53 -0500 |
commit | 92d8682926342d2b6aa5b2ecc02221e00e1573a0 (patch) | |
tree | 7f70b9cc2975716ab60ddd632b9fecf0a51b828d /net/ipv4/inetpeer.c | |
parent | 0131ba451e20239c5dc701027c1a2edef95e1a6e (diff) |
inetpeer: Move ICMP rate limiting state into inet_peer entries.
Like metrics, the ICMP rate limiting bits are cached state about
a destination. So move it into the inet_peer entries.
If an inet_peer cannot be bound (the reason is memory allocation
failure or similar), the policy is to allow.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/inetpeer.c')
-rw-r--r-- | net/ipv4/inetpeer.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index b6513b13d729..709fbb4132d7 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c | |||
@@ -513,6 +513,8 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create) | |||
513 | atomic_set(&p->ip_id_count, secure_ip_id(daddr->a4)); | 513 | atomic_set(&p->ip_id_count, secure_ip_id(daddr->a4)); |
514 | p->tcp_ts_stamp = 0; | 514 | p->tcp_ts_stamp = 0; |
515 | p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW; | 515 | p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW; |
516 | p->rate_tokens = 0; | ||
517 | p->rate_last = 0; | ||
516 | INIT_LIST_HEAD(&p->unused); | 518 | INIT_LIST_HEAD(&p->unused); |
517 | 519 | ||
518 | 520 | ||
@@ -580,3 +582,44 @@ void inet_putpeer(struct inet_peer *p) | |||
580 | local_bh_enable(); | 582 | local_bh_enable(); |
581 | } | 583 | } |
582 | EXPORT_SYMBOL_GPL(inet_putpeer); | 584 | EXPORT_SYMBOL_GPL(inet_putpeer); |
585 | |||
586 | /* | ||
587 | * Check transmit rate limitation for given message. | ||
588 | * The rate information is held in the inet_peer entries now. | ||
589 | * This function is generic and could be used for other purposes | ||
590 | * too. It uses a Token bucket filter as suggested by Alexey Kuznetsov. | ||
591 | * | ||
592 | * Note that the same inet_peer fields are modified by functions in | ||
593 | * route.c too, but these work for packet destinations while xrlim_allow | ||
594 | * works for icmp destinations. This means the rate limiting information | ||
595 | * for one "ip object" is shared - and these ICMPs are twice limited: | ||
596 | * by source and by destination. | ||
597 | * | ||
598 | * RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate | ||
599 | * SHOULD allow setting of rate limits | ||
600 | * | ||
601 | * Shared between ICMPv4 and ICMPv6. | ||
602 | */ | ||
603 | #define XRLIM_BURST_FACTOR 6 | ||
604 | bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout) | ||
605 | { | ||
606 | unsigned long now, token; | ||
607 | bool rc = false; | ||
608 | |||
609 | if (!peer) | ||
610 | return true; | ||
611 | |||
612 | token = peer->rate_tokens; | ||
613 | now = jiffies; | ||
614 | token += now - peer->rate_last; | ||
615 | peer->rate_last = now; | ||
616 | if (token > XRLIM_BURST_FACTOR * timeout) | ||
617 | token = XRLIM_BURST_FACTOR * timeout; | ||
618 | if (token >= timeout) { | ||
619 | token -= timeout; | ||
620 | rc = true; | ||
621 | } | ||
622 | peer->rate_tokens = token; | ||
623 | return rc; | ||
624 | } | ||
625 | EXPORT_SYMBOL(inet_peer_xrlim_allow); | ||