1 // Copyright 2015 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build freebsd 16 17 // Package limits provides routines to check and enforce certain resource 18 // limits on the Cloud SQL client proxy process. 19 package limits 20 21 import ( 22 "fmt" 23 "syscall" 24 25 "github.com/GoogleCloudPlatform/cloudsql-proxy/logging" 26 ) 27 28 var ( 29 // For overriding in unittests. 30 syscallGetrlimit = syscall.Getrlimit 31 syscallSetrlimit = syscall.Setrlimit 32 ) 33 34 // Each connection handled by the proxy requires two file descriptors, one 35 // for the local end of the connection and one for the remote. So, the proxy 36 // process should be able to open at least 8K file descriptors if it is to 37 // handle 4K connections to one instance. 38 const ExpectedFDs = 8500 39 40 // SetupFDLimits ensures that the process running the Cloud SQL proxy can have 41 // at least wantFDs number of open file descriptors. It returns an error if it 42 // cannot ensure the same. 43 func SetupFDLimits(wantFDs uint64) error { 44 rlim := &syscall.Rlimit{} 45 if err := syscallGetrlimit(syscall.RLIMIT_NOFILE, rlim); err != nil { 46 return fmt.Errorf("failed to read rlimit for max file descriptors: %v", err) 47 } 48 49 if uint64(rlim.Cur) >= wantFDs { 50 logging.Verbosef("current FDs rlimit set to %d, wanted limit is %d. Nothing to do here.", rlim.Cur, wantFDs) 51 return nil 52 } 53 54 // Linux man page: 55 // The soft limit is the value that the kernel enforces for the correā 56 // sponding resource. The hard limit acts as a ceiling for the soft limit: 57 // an unprivileged process may set only its soft limit to a value in the 58 // range from 0 up to the hard limit, and (irreversibly) lower its hard 59 // limit. A privileged process (under Linux: one with the CAP_SYS_RESOURCE 60 // capability in the initial user namespace) may make arbitrary changes to 61 // either limit value. 62 if uint64(rlim.Max) < wantFDs { 63 // When the hard limit is less than what is requested, let's just give it a 64 // shot, and if we fail, we fallback and try just setting the softlimit. 65 rlim2 := &syscall.Rlimit{} 66 rlim2.Max = int64(wantFDs) 67 rlim2.Cur = int64(wantFDs) 68 if err := syscallSetrlimit(syscall.RLIMIT_NOFILE, rlim2); err == nil { 69 logging.Verbosef("Rlimits for file descriptors set to {%v}", rlim2) 70 return nil 71 } 72 } 73 74 rlim.Cur = int64(wantFDs) 75 if err := syscallSetrlimit(syscall.RLIMIT_NOFILE, rlim); err != nil { 76 return fmt.Errorf("failed to set rlimit {%v} for max file descriptors: %v", rlim, err) 77 } 78 79 logging.Verbosef("Rlimits for file descriptors set to {%v}", rlim) 80 return nil 81 } 82