blob: 05ca2f901c6e516e16a7b27c65bee5c739d09317 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 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 Copyright (c) 2005 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
Tom Jones2e87d942024-05-06 14:53:57 +000038#ifndef _GNU_SOURCE
39#define _GNU_SOURCE
40#endif
41
Ed Warnickecb9cada2015-12-08 15:45:58 -070042#include <vppinfra/error.h>
43#include <vppinfra/os.h>
Damjan Marion4b661402024-02-29 16:14:27 +010044#include <vppinfra/bitmap.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070045#include <vppinfra/unix.h>
Damjan Marion40f48102023-08-07 01:07:09 +020046#include <vppinfra/format.h>
Damjan Marion4b661402024-02-29 16:14:27 +010047#ifdef __linux__
48#include <vppinfra/linux/sysfs.h>
Tom Jones2e87d942024-05-06 14:53:57 +000049#include <sched.h>
Tom Jonesf4c79962024-04-25 14:25:06 +000050#elif defined(__FreeBSD__)
Tom Jones2e87d942024-05-06 14:53:57 +000051#define _WANT_FREEBSD_BITSET
52#include <sys/cdefs.h>
Tom Jonesf4c79962024-04-25 14:25:06 +000053#include <sys/param.h>
Tom Jones2e87d942024-05-06 14:53:57 +000054#include <sys/types.h>
55#include <sys/cpuset.h>
56#include <sys/domainset.h>
57#include <sys/sysctl.h>
Damjan Marion4b661402024-02-29 16:14:27 +010058#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -070059
60#include <sys/stat.h>
61#include <sys/types.h>
62#include <sys/uio.h> /* writev */
63#include <fcntl.h>
64#include <stdio.h> /* for sprintf */
Damjan Marion40f48102023-08-07 01:07:09 +020065#include <limits.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070066
Damjan Mariondae1c7e2020-10-17 13:32:25 +020067__clib_export __thread uword __os_thread_index = 0;
68__clib_export __thread uword __os_numa_index = 0;
Damjan Marionf55f9b82017-05-10 21:06:28 +020069
Tom Jones828353f2024-08-14 09:23:11 +000070__clib_export clib_bitmap_t *os_get_cpu_affinity_bitmap (int pid);
71
Dave Barachc3799992016-08-15 11:12:27 -040072clib_error_t *
Dave Barach59b25652017-09-10 15:04:27 -040073clib_file_n_bytes (char *file, uword * result)
Ed Warnickecb9cada2015-12-08 15:45:58 -070074{
75 struct stat s;
76
77 if (stat (file, &s) < 0)
78 return clib_error_return_unix (0, "stat `%s'", file);
79
80 if (S_ISREG (s.st_mode))
81 *result = s.st_size;
82 else
83 *result = 0;
84
85 return /* no error */ 0;
86}
87
Dave Barachc3799992016-08-15 11:12:27 -040088clib_error_t *
Dave Barach59b25652017-09-10 15:04:27 -040089clib_file_read_contents (char *file, u8 * result, uword n_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -070090{
91 int fd = -1;
92 uword n_done, n_left;
Dave Barachc3799992016-08-15 11:12:27 -040093 clib_error_t *error = 0;
94 u8 *v = result;
Ed Warnickecb9cada2015-12-08 15:45:58 -070095
96 if ((fd = open (file, 0)) < 0)
Dave Barachc3799992016-08-15 11:12:27 -040097 return clib_error_return_unix (0, "open `%s'", file);
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 n_left = n_bytes;
100 n_done = 0;
101 while (n_left > 0)
102 {
103 int n_read;
104 if ((n_read = read (fd, v + n_done, n_left)) < 0)
105 {
106 error = clib_error_return_unix (0, "open `%s'", file);
107 goto done;
108 }
109
110 /* End of file. */
111 if (n_read == 0)
112 break;
113
114 n_left -= n_read;
115 n_done += n_read;
116 }
117
118 if (n_left > 0)
119 {
Dave Barachc3799992016-08-15 11:12:27 -0400120 error =
121 clib_error_return (0,
122 " `%s' expected to read %wd bytes; read only %wd",
123 file, n_bytes, n_bytes - n_left);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124 goto done;
125 }
126
Dave Barachc3799992016-08-15 11:12:27 -0400127done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700128 close (fd);
129 return error;
130}
131
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200132__clib_export clib_error_t *
Dave Barach59b25652017-09-10 15:04:27 -0400133clib_file_contents (char *file, u8 ** result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134{
135 uword n_bytes;
Dave Barachc3799992016-08-15 11:12:27 -0400136 clib_error_t *error = 0;
137 u8 *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138
Dave Barach59b25652017-09-10 15:04:27 -0400139 if ((error = clib_file_n_bytes (file, &n_bytes)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140 return error;
141
142 v = 0;
143 vec_resize (v, n_bytes);
144
Dave Barach59b25652017-09-10 15:04:27 -0400145 error = clib_file_read_contents (file, v, n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
147 if (error)
148 vec_free (v);
149 else
150 *result = v;
151
152 return error;
153}
154
Damjan Marion40f48102023-08-07 01:07:09 +0200155__clib_export u8 *
156clib_file_get_resolved_basename (char *fmt, ...)
157{
158 va_list va;
159 char *p, buffer[PATH_MAX];
160 u8 *link, *s = 0;
161 int r;
162
163 va_start (va, fmt);
164 link = va_format (0, fmt, &va);
165 va_end (va);
166 vec_add1 (link, 0);
167
168 r = readlink ((char *) link, buffer, sizeof (buffer) - 1);
169 vec_free (link);
170
171 if (r < 1)
172 return 0;
173
Dave Wallace05cc62d2023-10-09 18:05:47 -0400174 buffer[r] = 0;
Damjan Marion40f48102023-08-07 01:07:09 +0200175 p = buffer + r - 1;
176 while (p > buffer && p[-1] != '/')
177 p--;
178
179 while (p[0])
180 vec_add1 (s, p++[0]);
181
Damjan Marion08600cc2023-10-04 18:03:18 +0200182 vec_add1 (s, 0);
Damjan Marion40f48102023-08-07 01:07:09 +0200183 return s;
184}
185
Dave Barachc3799992016-08-15 11:12:27 -0400186clib_error_t *
187unix_proc_file_contents (char *file, u8 ** result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188{
189 u8 *rv = 0;
190 uword pos;
191 int bytes, fd;
192
193 /* Unfortunately, stat(/proc/XXX) returns zero... */
194 fd = open (file, O_RDONLY);
195
196 if (fd < 0)
197 return clib_error_return_unix (0, "open `%s'", file);
198
Dave Barachc3799992016-08-15 11:12:27 -0400199 vec_validate (rv, 4095);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200 pos = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400201 while (1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 {
Dave Barachc3799992016-08-15 11:12:27 -0400203 bytes = read (fd, rv + pos, 4096);
204 if (bytes < 0)
205 {
206 close (fd);
207 vec_free (rv);
208 return clib_error_return_unix (0, "read '%s'", file);
209 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210
Dave Barachc3799992016-08-15 11:12:27 -0400211 if (bytes == 0)
212 {
Damjan Marion8bea5892022-04-04 22:40:45 +0200213 vec_set_len (rv, pos);
Dave Barachc3799992016-08-15 11:12:27 -0400214 break;
215 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216 pos += bytes;
Dave Barachc3799992016-08-15 11:12:27 -0400217 vec_validate (rv, pos + 4095);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218 }
219 *result = rv;
220 close (fd);
221 return 0;
222}
223
Benoît Ganne448f08b2024-06-17 15:32:12 +0200224__clib_export __clib_weak void
Dave Barachc3799992016-08-15 11:12:27 -0400225os_panic (void)
226{
227 abort ();
228}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229
Benoît Ganne448f08b2024-06-17 15:32:12 +0200230__clib_export __clib_weak void
Dave Barachc3799992016-08-15 11:12:27 -0400231os_exit (int code)
232{
233 exit (code);
234}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235
Benoît Ganne448f08b2024-06-17 15:32:12 +0200236__clib_export __clib_weak void
237os_puts (u8 *string, uword string_length, uword is_error)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238{
Damjan Marionf55f9b82017-05-10 21:06:28 +0200239 int cpu = os_get_thread_index ();
240 int nthreads = os_get_nthreads ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241 char buf[64];
242 int fd = is_error ? 2 : 1;
243 struct iovec iovs[2];
244 int n_iovs = 0;
245
Damjan Marionf55f9b82017-05-10 21:06:28 +0200246 if (nthreads > 1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 {
Dave Barachc3799992016-08-15 11:12:27 -0400248 snprintf (buf, sizeof (buf), "%d: ", cpu);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249
250 iovs[n_iovs].iov_base = buf;
251 iovs[n_iovs].iov_len = strlen (buf);
252 n_iovs++;
253 }
254
255 iovs[n_iovs].iov_base = string;
256 iovs[n_iovs].iov_len = string_length;
257 n_iovs++;
258
259 if (writev (fd, iovs, n_iovs) < 0)
260 ;
261}
262
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200263__clib_export __clib_weak void
Dave Barachc3799992016-08-15 11:12:27 -0400264os_out_of_memory (void)
265{
266 os_panic ();
267}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700268
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200269__clib_export __clib_weak uword
Damjan Marionf55f9b82017-05-10 21:06:28 +0200270os_get_nthreads (void)
Dave Barachc3799992016-08-15 11:12:27 -0400271{
272 return 1;
273}
274
Damjan Marion4b661402024-02-29 16:14:27 +0100275__clib_export clib_bitmap_t *
276os_get_online_cpu_core_bitmap ()
277{
278#if __linux__
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000279 return clib_sysfs_read_bitmap ("/sys/devices/system/cpu/online");
Tom Jones828353f2024-08-14 09:23:11 +0000280#elif defined(__FreeBSD__)
281 return os_get_cpu_affinity_bitmap (0);
Damjan Marion4b661402024-02-29 16:14:27 +0100282#else
283 return 0;
284#endif
285}
286
287__clib_export clib_bitmap_t *
Tom Jones2e87d942024-05-06 14:53:57 +0000288os_get_cpu_affinity_bitmap (int pid)
289{
290#if __linux
291 int index, ret;
292 cpu_set_t cpuset;
293 uword *affinity_cpus;
294
295 clib_bitmap_alloc (affinity_cpus, sizeof (cpu_set_t));
296 clib_bitmap_zero (affinity_cpus);
297
Renato Botelho do Couto7f3c2172024-06-21 14:00:10 +0000298 CPU_ZERO_S (sizeof (cpu_set_t), &cpuset);
Tom Jones2e87d942024-05-06 14:53:57 +0000299
300 ret = sched_getaffinity (0, sizeof (cpu_set_t), &cpuset);
301
302 if (ret < 0)
303 {
304 clib_bitmap_free (affinity_cpus);
305 return 0;
306 }
307
308 for (index = 0; index < sizeof (cpu_set_t); index++)
Renato Botelho do Couto7f3c2172024-06-21 14:00:10 +0000309 if (CPU_ISSET_S (index, sizeof (cpu_set_t), &cpuset))
Tom Jones2e87d942024-05-06 14:53:57 +0000310 clib_bitmap_set (affinity_cpus, index, 1);
311 return affinity_cpus;
312#elif defined(__FreeBSD__)
313 cpuset_t mask;
314 uword *r = NULL;
315
Tom Jones828353f2024-08-14 09:23:11 +0000316 clib_bitmap_alloc (r, sizeof (CPU_SETSIZE));
317 clib_bitmap_zero (r);
318
Tom Jones2e87d942024-05-06 14:53:57 +0000319 if (cpuset_getaffinity (CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, -1,
320 sizeof (mask), &mask) != 0)
321 {
322 clib_bitmap_free (r);
323 return NULL;
324 }
325
326 for (int bit = 0; bit < CPU_SETSIZE; bit++)
327 clib_bitmap_set (r, bit, CPU_ISSET (bit, &mask));
328
329 return r;
330#else
331 return NULL;
332#endif
333}
334
335__clib_export clib_bitmap_t *
Damjan Marion4b661402024-02-29 16:14:27 +0100336os_get_online_cpu_node_bitmap ()
337{
338#if __linux__
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000339 return clib_sysfs_read_bitmap ("/sys/devices/system/node/online");
Damjan Marion4b661402024-02-29 16:14:27 +0100340#else
341 return 0;
342#endif
343}
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000344__clib_export clib_bitmap_t *
345os_get_cpu_on_node_bitmap (int node)
346{
347#if __linux__
348 return clib_sysfs_read_bitmap ("/sys/devices/system/node/node%u/cpulist",
349 node);
350#else
351 return 0;
352#endif
353}
354
355__clib_export clib_bitmap_t *
356os_get_cpu_with_memory_bitmap ()
357{
358#if __linux__
359 return clib_sysfs_read_bitmap ("/sys/devices/system/node/has_memory");
360#else
361 return 0;
362#endif
363}
364
365__clib_export int
366os_get_cpu_phys_core_id (int cpu_id)
367{
368#if __linux
369 int core_id = -1;
370 clib_error_t *err;
371 u8 *p;
372
373 p =
374 format (0, "/sys/devices/system/cpu/cpu%u/topology/core_id%c", cpu_id, 0);
375 err = clib_sysfs_read ((char *) p, "%d", &core_id);
376 vec_free (p);
377 if (err)
378 {
379 clib_error_free (err);
380 return -1;
381 }
382 return core_id;
383#else
384 return -1;
385#endif
386}
Damjan Marion4b661402024-02-29 16:14:27 +0100387
Tom Jonesab479932024-04-24 10:30:20 +0000388__clib_export u8 *
389os_get_exec_path ()
390{
391 u8 *rv = 0;
392#ifdef __linux__
393 char tmp[PATH_MAX];
394 ssize_t sz = readlink ("/proc/self/exe", tmp, sizeof (tmp));
395
396 if (sz <= 0)
397 return 0;
398#else
399 char tmp[MAXPATHLEN];
400 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
401 size_t sz = MAXPATHLEN;
402
403 if (sysctl (mib, 4, tmp, &sz, NULL, 0) == -1)
404 return 0;
405#endif
406 vec_add (rv, tmp, sz);
407 return rv;
408}
409
Dave Barachc3799992016-08-15 11:12:27 -0400410/*
411 * fd.io coding-style-patch-verification: ON
412 *
413 * Local Variables:
414 * eval: (c-set-style "gnu")
415 * End:
416 */