optmem_max being used in tx zerocopy,
we want to be able to control it on a netns basis.
Following patch changes two tests.
Tested:
oqq130:~# cat /proc/sys/net/core/optmem_max
131072
oqq130:~# echo 
1000000 >/proc/sys/net/core/optmem_max
oqq130:~# cat /proc/sys/net/core/optmem_max
1000000
oqq130:~# unshare -n
oqq130:~# cat /proc/sys/net/core/optmem_max
131072
oqq130:~# exit
logout
oqq130:~# cat /proc/sys/net/core/optmem_max
1000000
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Acked-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
        struct ctl_table_header *sysctl_hdr;
 
        int     sysctl_somaxconn;
+       int     sysctl_optmem_max;
        u8      sysctl_txrehash;
 
 #ifdef CONFIG_PROC_FS
 
 extern __u32 sysctl_rmem_max;
 
 extern int sysctl_tstamp_allow_data;
-extern int sysctl_optmem_max;
 
 extern __u32 sysctl_wmem_default;
 extern __u32 sysctl_rmem_default;
 
 static int bpf_sk_storage_charge(struct bpf_local_storage_map *smap,
                                 void *owner, u32 size)
 {
-       int optmem_max = READ_ONCE(sysctl_optmem_max);
        struct sock *sk = (struct sock *)owner;
+       int optmem_max;
 
+       optmem_max = READ_ONCE(sock_net(sk)->core.sysctl_optmem_max);
        /* same check as in sock_kmalloc() */
        if (size <= optmem_max &&
            atomic_read(&sk->sk_omem_alloc) + size < optmem_max) {
 
  */
 static bool __sk_filter_charge(struct sock *sk, struct sk_filter *fp)
 {
+       int optmem_max = READ_ONCE(sock_net(sk)->core.sysctl_optmem_max);
        u32 filter_size = bpf_prog_size(fp->prog->len);
-       int optmem_max = READ_ONCE(sysctl_optmem_max);
 
        /* same check as in sock_kmalloc() */
        if (filter_size <= optmem_max &&
 int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk)
 {
        struct bpf_prog *prog = __get_filter(fprog, sk);
-       int err;
+       int err, optmem_max;
 
        if (IS_ERR(prog))
                return PTR_ERR(prog);
 
-       if (bpf_prog_size(prog->len) > READ_ONCE(sysctl_optmem_max))
+       optmem_max = READ_ONCE(sock_net(sk)->core.sysctl_optmem_max);
+       if (bpf_prog_size(prog->len) > optmem_max)
                err = -ENOMEM;
        else
                err = reuseport_attach_prog(sk, prog);
 int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk)
 {
        struct bpf_prog *prog;
-       int err;
+       int err, optmem_max;
 
        if (sock_flag(sk, SOCK_FILTER_LOCKED))
                return -EPERM;
                }
        } else {
                /* BPF_PROG_TYPE_SOCKET_FILTER */
-               if (bpf_prog_size(prog->len) > READ_ONCE(sysctl_optmem_max)) {
+               optmem_max = READ_ONCE(sock_net(sk)->core.sysctl_optmem_max);
+               if (bpf_prog_size(prog->len) > optmem_max) {
                        err = -ENOMEM;
                        goto err_prog_put;
                }
 
 static int __net_init net_defaults_init_net(struct net *net)
 {
        net->core.sysctl_somaxconn = SOMAXCONN;
+       /* Limits per socket sk_omem_alloc usage.
+        * TCP zerocopy regular usage needs 128 KB.
+        */
+       net->core.sysctl_optmem_max = 128 * 1024;
        net->core.sysctl_txrehash = SOCK_TXREHASH_ENABLED;
 
        return 0;
 
 __u32 sysctl_wmem_default __read_mostly = SK_WMEM_MAX;
 __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX;
 
-/* Limits per socket sk_omem_alloc usage.
- * TCP zerocopy regular usage needs 128 KB.
- */
-int sysctl_optmem_max __read_mostly = 128 * 1024;
-EXPORT_SYMBOL(sysctl_optmem_max);
-
 int sysctl_tstamp_allow_data __read_mostly = 1;
 
 DEFINE_STATIC_KEY_FALSE(memalloc_socks_key);
 
        /* small safe race: SKB_TRUESIZE may differ from final skb->truesize */
        if (atomic_read(&sk->sk_omem_alloc) + SKB_TRUESIZE(size) >
-           READ_ONCE(sysctl_optmem_max))
+           READ_ONCE(sock_net(sk)->core.sysctl_optmem_max))
                return NULL;
 
        skb = alloc_skb(size, priority);
  */
 void *sock_kmalloc(struct sock *sk, int size, gfp_t priority)
 {
-       int optmem_max = READ_ONCE(sysctl_optmem_max);
+       int optmem_max = READ_ONCE(sock_net(sk)->core.sysctl_optmem_max);
 
        if ((unsigned int)size <= optmem_max &&
            atomic_read(&sk->sk_omem_alloc) + size < optmem_max) {
 
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       {
-               .procname       = "optmem_max",
-               .data           = &sysctl_optmem_max,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec
-       },
        {
                .procname       = "tstamp_allow_data",
                .data           = &sysctl_tstamp_allow_data,
                .extra1         = SYSCTL_ZERO,
                .proc_handler   = proc_dointvec_minmax
        },
+       {
+               .procname       = "optmem_max",
+               .data           = &init_net.core.sysctl_optmem_max,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .extra1         = SYSCTL_ZERO,
+               .proc_handler   = proc_dointvec_minmax
+       },
        {
                .procname       = "txrehash",
                .data           = &init_net.core.sysctl_txrehash,
 
 
        if (optlen < GROUP_FILTER_SIZE(0))
                return -EINVAL;
-       if (optlen > READ_ONCE(sysctl_optmem_max))
+       if (optlen > READ_ONCE(sock_net(sk)->core.sysctl_optmem_max))
                return -ENOBUFS;
 
        gsf = memdup_sockptr(optval, optlen);
 
        if (optlen < size0)
                return -EINVAL;
-       if (optlen > READ_ONCE(sysctl_optmem_max) - 4)
+       if (optlen > READ_ONCE(sock_net(sk)->core.sysctl_optmem_max) - 4)
                return -ENOBUFS;
 
        p = kmalloc(optlen + 4, GFP_KERNEL);
 
                if (optlen < IP_MSFILTER_SIZE(0))
                        goto e_inval;
-               if (optlen > READ_ONCE(sysctl_optmem_max)) {
+               if (optlen > READ_ONCE(net->core.sysctl_optmem_max)) {
                        err = -ENOBUFS;
                        break;
                }
 
 
        if (optlen < GROUP_FILTER_SIZE(0))
                return -EINVAL;
-       if (optlen > READ_ONCE(sysctl_optmem_max))
+       if (optlen > READ_ONCE(sock_net(sk)->core.sysctl_optmem_max))
                return -ENOBUFS;
 
        gsf = memdup_sockptr(optval, optlen);
 
        if (optlen < size0)
                return -EINVAL;
-       if (optlen > READ_ONCE(sysctl_optmem_max) - 4)
+       if (optlen > READ_ONCE(sock_net(sk)->core.sysctl_optmem_max) - 4)
                return -ENOBUFS;
 
        p = kmalloc(optlen + 4, GFP_KERNEL);