Skip to content

Commit

Permalink
[UDP]: Add memory accounting.
Browse files Browse the repository at this point in the history
Signed-off-by: Takahiro Yasui <tyasui@redhat.com>
Signed-off-by: Hideo Aoki <haoki@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Hideo Aoki authored and David S. Miller committed Jan 28, 2008
1 parent 3ab224b commit 95766ff
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 7 deletions.
27 changes: 27 additions & 0 deletions Documentation/networking/ip-sysctl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,33 @@ tcp_dma_copybreak - INTEGER
and CONFIG_NET_DMA is enabled.
Default: 4096

UDP variables:

udp_mem - vector of 3 INTEGERs: min, pressure, max
Number of pages allowed for queueing by all UDP sockets.

min: Below this number of pages UDP is not bothered about its
memory appetite. When amount of memory allocated by UDP exceeds
this number, UDP starts to moderate memory usage.

pressure: This value was introduced to follow format of tcp_mem.

max: Number of pages allowed for queueing by all UDP sockets.

Default is calculated at boot time from amount of available memory.

udp_rmem_min - INTEGER
Minimal size of receive buffer used by UDP sockets in moderation.
Each UDP socket is able to use the size for receiving data, even if
total pages of UDP sockets exceed udp_mem pressure. The unit is byte.
Default: 4096

udp_wmem_min - INTEGER
Minimal size of send buffer used by UDP sockets in moderation.
Each UDP socket is able to use the size for sending data, even if
total pages of UDP sockets exceed udp_mem pressure. The unit is byte.
Default: 4096

CIPSOv4 Variables:

cipso_cache_enable - BOOLEAN
Expand Down
9 changes: 9 additions & 0 deletions include/net/udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ extern rwlock_t udp_hash_lock;

extern struct proto udp_prot;

extern atomic_t udp_memory_allocated;

/* sysctl variables for udp */
extern int sysctl_udp_mem[3];
extern int sysctl_udp_rmem_min;
extern int sysctl_udp_wmem_min;

struct sk_buff;

/*
Expand Down Expand Up @@ -198,4 +205,6 @@ extern void udp_proc_unregister(struct udp_seq_afinfo *afinfo);
extern int udp4_proc_init(void);
extern void udp4_proc_exit(void);
#endif

extern void udp_init(void);
#endif /* _UDP_H */
5 changes: 5 additions & 0 deletions net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ void inet_sock_destruct(struct sock *sk)
__skb_queue_purge(&sk->sk_receive_queue);
__skb_queue_purge(&sk->sk_error_queue);

sk_mem_reclaim(sk);

if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {
printk("Attempt to release TCP socket in state %d %p\n",
sk->sk_state, sk);
Expand Down Expand Up @@ -1417,6 +1419,9 @@ static int __init inet_init(void)
/* Setup TCP slab cache for open requests. */
tcp_init();

/* Setup UDP memory threshold */
udp_init();

/* Add UDP-Lite (RFC 3828) */
udplite4_register();

Expand Down
3 changes: 2 additions & 1 deletion net/ipv4/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
sock_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
atomic_read(&tcp_memory_allocated));
seq_printf(seq, "UDP: inuse %d\n", sock_prot_inuse(&udp_prot));
seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse(&udp_prot),
atomic_read(&udp_memory_allocated));
seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse(&udplite_prot));
seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse(&raw_prot));
seq_printf(seq, "FRAG: inuse %d memory %d\n",
Expand Down
31 changes: 31 additions & 0 deletions net/ipv4/sysctl_net_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <net/ip.h>
#include <net/route.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <net/cipso_ipv4.h>
#include <net/inet_frag.h>

Expand Down Expand Up @@ -812,6 +813,36 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = CTL_UNNUMBERED,
.procname = "udp_mem",
.data = &sysctl_udp_mem,
.maxlen = sizeof(sysctl_udp_mem),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &zero
},
{
.ctl_name = CTL_UNNUMBERED,
.procname = "udp_rmem_min",
.data = &sysctl_udp_rmem_min,
.maxlen = sizeof(sysctl_udp_rmem_min),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &zero
},
{
.ctl_name = CTL_UNNUMBERED,
.procname = "udp_wmem_min",
.data = &sysctl_udp_wmem_min,
.maxlen = sizeof(sysctl_udp_wmem_min),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &zero
},
{ .ctl_name = 0 }
};

Expand Down
57 changes: 55 additions & 2 deletions net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
#include <linux/bootmem.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/module.h>
Expand Down Expand Up @@ -118,6 +119,17 @@ EXPORT_SYMBOL(udp_stats_in6);
struct hlist_head udp_hash[UDP_HTABLE_SIZE];
DEFINE_RWLOCK(udp_hash_lock);

int sysctl_udp_mem[3] __read_mostly;
int sysctl_udp_rmem_min __read_mostly;
int sysctl_udp_wmem_min __read_mostly;

EXPORT_SYMBOL(sysctl_udp_mem);
EXPORT_SYMBOL(sysctl_udp_rmem_min);
EXPORT_SYMBOL(sysctl_udp_wmem_min);

atomic_t udp_memory_allocated;
EXPORT_SYMBOL(udp_memory_allocated);

static inline int __udp_lib_lport_inuse(__u16 num,
const struct hlist_head udptable[])
{
Expand Down Expand Up @@ -901,13 +913,17 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
err = ulen;

out_free:
lock_sock(sk);
skb_free_datagram(sk, skb);
release_sock(sk);
out:
return err;

csum_copy_err:
lock_sock(sk);
if (!skb_kill_datagram(sk, skb, flags))
UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
release_sock(sk);

if (noblock)
return -EAGAIN;
Expand Down Expand Up @@ -1072,7 +1088,15 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
skb1 = skb_clone(skb, GFP_ATOMIC);

if (skb1) {
int ret = udp_queue_rcv_skb(sk, skb1);
int ret = 0;

bh_lock_sock_nested(sk);
if (!sock_owned_by_user(sk))
ret = udp_queue_rcv_skb(sk, skb1);
else
sk_add_backlog(sk, skb1);
bh_unlock_sock(sk);

if (ret > 0)
/* we should probably re-process instead
* of dropping packets here. */
Expand Down Expand Up @@ -1165,7 +1189,13 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
inet_iif(skb), udptable);

if (sk != NULL) {
int ret = udp_queue_rcv_skb(sk, skb);
int ret = 0;
bh_lock_sock_nested(sk);
if (!sock_owned_by_user(sk))
ret = udp_queue_rcv_skb(sk, skb);
else
sk_add_backlog(sk, skb);
bh_unlock_sock(sk);
sock_put(sk);

/* a return value > 0 means to resubmit the input, but
Expand Down Expand Up @@ -1460,6 +1490,10 @@ struct proto udp_prot = {
.hash = udp_lib_hash,
.unhash = udp_lib_unhash,
.get_port = udp_v4_get_port,
.memory_allocated = &udp_memory_allocated,
.sysctl_mem = sysctl_udp_mem,
.sysctl_wmem = &sysctl_udp_wmem_min,
.sysctl_rmem = &sysctl_udp_rmem_min,
.obj_size = sizeof(struct udp_sock),
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_udp_setsockopt,
Expand Down Expand Up @@ -1655,6 +1689,25 @@ void udp4_proc_exit(void)
}
#endif /* CONFIG_PROC_FS */

void __init udp_init(void)
{
unsigned long limit;

/* Set the pressure threshold up by the same strategy of TCP. It is a
* fraction of global memory that is up to 1/2 at 256 MB, decreasing
* toward zero with the amount of memory, with a floor of 128 pages.
*/
limit = min(nr_all_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
limit = (limit * (nr_all_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
limit = max(limit, 128UL);
sysctl_udp_mem[0] = limit / 4 * 3;
sysctl_udp_mem[1] = limit;
sysctl_udp_mem[2] = sysctl_udp_mem[0] * 2;

sysctl_udp_rmem_min = SK_MEM_QUANTUM;
sysctl_udp_wmem_min = SK_MEM_QUANTUM;
}

EXPORT_SYMBOL(udp_disconnect);
EXPORT_SYMBOL(udp_hash);
EXPORT_SYMBOL(udp_hash_lock);
Expand Down
32 changes: 28 additions & 4 deletions net/ipv6/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,17 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
err = ulen;

out_free:
lock_sock(sk);
skb_free_datagram(sk, skb);
release_sock(sk);
out:
return err;

csum_copy_err:
lock_sock(sk);
if (!skb_kill_datagram(sk, skb, flags))
UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite);
release_sock(sk);

if (flags & MSG_DONTWAIT)
return -EAGAIN;
Expand Down Expand Up @@ -366,10 +370,21 @@ static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr,
while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr,
uh->source, saddr, dif))) {
struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC);
if (buff)
udpv6_queue_rcv_skb(sk2, buff);
if (buff) {
bh_lock_sock_nested(sk2);
if (!sock_owned_by_user(sk2))
udpv6_queue_rcv_skb(sk2, buff);
else
sk_add_backlog(sk2, buff);
bh_unlock_sock(sk2);
}
}
udpv6_queue_rcv_skb(sk, skb);
bh_lock_sock_nested(sk);
if (!sock_owned_by_user(sk))
udpv6_queue_rcv_skb(sk, skb);
else
sk_add_backlog(sk, skb);
bh_unlock_sock(sk);
out:
read_unlock(&udp_hash_lock);
return 0;
Expand Down Expand Up @@ -482,7 +497,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],

/* deliver */

udpv6_queue_rcv_skb(sk, skb);
bh_lock_sock_nested(sk);
if (!sock_owned_by_user(sk))
udpv6_queue_rcv_skb(sk, skb);
else
sk_add_backlog(sk, skb);
bh_unlock_sock(sk);
sock_put(sk);
return 0;

Expand Down Expand Up @@ -994,6 +1014,10 @@ struct proto udpv6_prot = {
.hash = udp_lib_hash,
.unhash = udp_lib_unhash,
.get_port = udp_v6_get_port,
.memory_allocated = &udp_memory_allocated,
.sysctl_mem = sysctl_udp_mem,
.sysctl_wmem = &sysctl_udp_wmem_min,
.sysctl_rmem = &sysctl_udp_rmem_min,
.obj_size = sizeof(struct udp6_sock),
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_udpv6_setsockopt,
Expand Down

0 comments on commit 95766ff

Please sign in to comment.