f92f9ef564e2771ef7f978ce3ef75580a08767a1
[vpp.git] / src / vlib / linux / sysfs.c
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
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
16 #include <vlib/vlib.h>
17 #include <vlib/unix/unix.h>
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <dirent.h>
23
24 clib_error_t *
25 vlib_sysfs_write (char *file_name, char *fmt, ...)
26 {
27   u8 *s;
28   int fd;
29   clib_error_t *error = 0;
30
31   fd = open (file_name, O_WRONLY);
32   if (fd < 0)
33     return clib_error_return_unix (0, "open `%s'", file_name);
34
35   va_list va;
36   va_start (va, fmt);
37   s = va_format (0, fmt, &va);
38   va_end (va);
39
40   if (write (fd, s, vec_len (s)) < 0)
41     error = clib_error_return_unix (0, "write `%s'", file_name);
42
43   vec_free (s);
44   close (fd);
45   return error;
46 }
47
48 clib_error_t *
49 vlib_sysfs_read (char *file_name, char *fmt, ...)
50 {
51   unformat_input_t input;
52   u8 *s = 0;
53   int fd;
54   ssize_t sz;
55   uword result;
56
57   fd = open (file_name, O_RDONLY);
58   if (fd < 0)
59     return clib_error_return_unix (0, "open `%s'", file_name);
60
61   vec_validate (s, 4095);
62
63   sz = read (fd, s, vec_len (s));
64   if (sz < 0)
65     {
66       close (fd);
67       vec_free (s);
68       return clib_error_return_unix (0, "read `%s'", file_name);
69     }
70
71   _vec_len (s) = sz;
72   unformat_init_vector (&input, s);
73
74   va_list va;
75   va_start (va, fmt);
76   result = va_unformat (&input, fmt, &va);
77   va_end (va);
78
79   vec_free (s);
80   close (fd);
81
82   if (result == 0)
83     return clib_error_return (0, "unformat error");
84
85   return 0;
86 }
87
88 u8 *
89 vlib_sysfs_link_to_name (char *link)
90 {
91   char *p, buffer[64];
92   unformat_input_t in;
93   u8 *s = 0;
94   int r;
95
96   r = readlink (link, buffer, sizeof (buffer) - 1);
97
98   if (r < 0)
99     return 0;
100
101   buffer[r] = 0;
102   p = strrchr (buffer, '/');
103
104   if (!p)
105     return 0;
106
107   unformat_init_string (&in, p + 1, strlen (p + 1));
108   if (unformat (&in, "%s", &s) != 1)
109     clib_unix_warning ("no string?");
110   unformat_free (&in);
111
112   return s;
113 }
114
115 clib_error_t *
116 vlib_sysfs_set_nr_hugepages (unsigned int numa_node, int page_size, int nr)
117 {
118   clib_error_t *error = 0;
119   struct stat sb;
120   u8 *p = 0;
121
122   p = format (p, "/sys/devices/system/node/node%u%c", numa_node, 0);
123
124   if (stat ((char *) p, &sb) == 0)
125     {
126       if (S_ISDIR (sb.st_mode) == 0)
127         {
128           error = clib_error_return (0, "'%s' is not directory", p);
129           goto done;
130         }
131     }
132   else if (numa_node == 0)
133     {
134       vec_reset_length (p);
135       p = format (p, "/sys/kernel/mm%c", 0);
136       if (stat ((char *) p, &sb) < 0 || S_ISDIR (sb.st_mode) == 0)
137         {
138           error = clib_error_return (0, "'%s' does not exist or it is not "
139                                      "directory", p);
140           goto done;
141         }
142     }
143   else
144     {
145       error = clib_error_return (0, "'%s' does not exist", p);
146       goto done;
147     }
148
149   _vec_len (p) -= 1;
150   p = format (p, "/hugepages/hugepages-%ukB/nr_hugepages%c", page_size, 0);
151   vlib_sysfs_write ((char *) p, "%d", nr);
152
153 done:
154   vec_free (p);
155   return error;
156 }
157
158
159 static clib_error_t *
160 vlib_sysfs_get_xxx_hugepages (char *type, unsigned int numa_node,
161                               int page_size, int *val)
162 {
163   clib_error_t *error = 0;
164   struct stat sb;
165   u8 *p = 0;
166
167   p = format (p, "/sys/devices/system/node/node%u%c", numa_node, 0);
168
169   if (stat ((char *) p, &sb) == 0)
170     {
171       if (S_ISDIR (sb.st_mode) == 0)
172         {
173           error = clib_error_return (0, "'%s' is not directory", p);
174           goto done;
175         }
176     }
177   else if (numa_node == 0)
178     {
179       vec_reset_length (p);
180       p = format (p, "/sys/kernel/mm%c", 0);
181       if (stat ((char *) p, &sb) < 0 || S_ISDIR (sb.st_mode) == 0)
182         {
183           error = clib_error_return (0, "'%s' does not exist or it is not "
184                                      "directory", p);
185           goto done;
186         }
187     }
188   else
189     {
190       error = clib_error_return (0, "'%s' does not exist", p);
191       goto done;
192     }
193
194   _vec_len (p) -= 1;
195   p = format (p, "/hugepages/hugepages-%ukB/%s_hugepages%c", page_size,
196               type, 0);
197   error = vlib_sysfs_read ((char *) p, "%d", val);
198
199 done:
200   vec_free (p);
201   return error;
202 }
203
204 clib_error_t *
205 vlib_sysfs_get_free_hugepages (unsigned int numa_node, int page_size, int *v)
206 {
207   return vlib_sysfs_get_xxx_hugepages ("free", numa_node, page_size, v);
208 }
209
210 clib_error_t *
211 vlib_sysfs_get_nr_hugepages (unsigned int numa_node, int page_size, int *v)
212 {
213   return vlib_sysfs_get_xxx_hugepages ("nr", numa_node, page_size, v);
214 }
215
216 clib_error_t *
217 vlib_sysfs_get_surplus_hugepages (unsigned int numa_node, int page_size,
218                                   int *v)
219 {
220   return vlib_sysfs_get_xxx_hugepages ("surplus", numa_node, page_size, v);
221 }
222
223 clib_error_t *
224 vlib_sysfs_prealloc_hugepages (unsigned int numa_node, int page_size, int nr)
225 {
226   clib_error_t *error = 0;
227   int n, needed;
228   error = vlib_sysfs_get_free_hugepages (numa_node, page_size, &n);
229   if (error)
230     return error;
231   needed = nr - n;
232   if (needed <= 0)
233     return 0;
234
235   error = vlib_sysfs_get_nr_hugepages (numa_node, page_size, &n);
236   if (error)
237     return error;
238   clib_warning ("pre-allocating %u additional %uK hugepages on numa node %u",
239                 needed, page_size, numa_node);
240   return vlib_sysfs_set_nr_hugepages (numa_node, page_size, n + needed);
241 }
242
243
244 /*
245  * fd.io coding-style-patch-verification: ON
246  *
247  * Local Variables:
248  * eval: (c-set-style "gnu")
249  * End:
250  */