blob: 31c0a489e8dfbcf4bac373880c6b1e6a323bdec1 [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
Dave Barachc3799992016-08-15 11:12:27 -040070clib_error_t *
Dave Barach59b25652017-09-10 15:04:27 -040071clib_file_n_bytes (char *file, uword * result)
Ed Warnickecb9cada2015-12-08 15:45:58 -070072{
73 struct stat s;
74
75 if (stat (file, &s) < 0)
76 return clib_error_return_unix (0, "stat `%s'", file);
77
78 if (S_ISREG (s.st_mode))
79 *result = s.st_size;
80 else
81 *result = 0;
82
83 return /* no error */ 0;
84}
85
Dave Barachc3799992016-08-15 11:12:27 -040086clib_error_t *
Dave Barach59b25652017-09-10 15:04:27 -040087clib_file_read_contents (char *file, u8 * result, uword n_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -070088{
89 int fd = -1;
90 uword n_done, n_left;
Dave Barachc3799992016-08-15 11:12:27 -040091 clib_error_t *error = 0;
92 u8 *v = result;
Ed Warnickecb9cada2015-12-08 15:45:58 -070093
94 if ((fd = open (file, 0)) < 0)
Dave Barachc3799992016-08-15 11:12:27 -040095 return clib_error_return_unix (0, "open `%s'", file);
Ed Warnickecb9cada2015-12-08 15:45:58 -070096
97 n_left = n_bytes;
98 n_done = 0;
99 while (n_left > 0)
100 {
101 int n_read;
102 if ((n_read = read (fd, v + n_done, n_left)) < 0)
103 {
104 error = clib_error_return_unix (0, "open `%s'", file);
105 goto done;
106 }
107
108 /* End of file. */
109 if (n_read == 0)
110 break;
111
112 n_left -= n_read;
113 n_done += n_read;
114 }
115
116 if (n_left > 0)
117 {
Dave Barachc3799992016-08-15 11:12:27 -0400118 error =
119 clib_error_return (0,
120 " `%s' expected to read %wd bytes; read only %wd",
121 file, n_bytes, n_bytes - n_left);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122 goto done;
123 }
124
Dave Barachc3799992016-08-15 11:12:27 -0400125done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126 close (fd);
127 return error;
128}
129
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200130__clib_export clib_error_t *
Dave Barach59b25652017-09-10 15:04:27 -0400131clib_file_contents (char *file, u8 ** result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132{
133 uword n_bytes;
Dave Barachc3799992016-08-15 11:12:27 -0400134 clib_error_t *error = 0;
135 u8 *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
Dave Barach59b25652017-09-10 15:04:27 -0400137 if ((error = clib_file_n_bytes (file, &n_bytes)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138 return error;
139
140 v = 0;
141 vec_resize (v, n_bytes);
142
Dave Barach59b25652017-09-10 15:04:27 -0400143 error = clib_file_read_contents (file, v, n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144
145 if (error)
146 vec_free (v);
147 else
148 *result = v;
149
150 return error;
151}
152
Damjan Marion40f48102023-08-07 01:07:09 +0200153__clib_export u8 *
154clib_file_get_resolved_basename (char *fmt, ...)
155{
156 va_list va;
157 char *p, buffer[PATH_MAX];
158 u8 *link, *s = 0;
159 int r;
160
161 va_start (va, fmt);
162 link = va_format (0, fmt, &va);
163 va_end (va);
164 vec_add1 (link, 0);
165
166 r = readlink ((char *) link, buffer, sizeof (buffer) - 1);
167 vec_free (link);
168
169 if (r < 1)
170 return 0;
171
Dave Wallace05cc62d2023-10-09 18:05:47 -0400172 buffer[r] = 0;
Damjan Marion40f48102023-08-07 01:07:09 +0200173 p = buffer + r - 1;
174 while (p > buffer && p[-1] != '/')
175 p--;
176
177 while (p[0])
178 vec_add1 (s, p++[0]);
179
Damjan Marion08600cc2023-10-04 18:03:18 +0200180 vec_add1 (s, 0);
Damjan Marion40f48102023-08-07 01:07:09 +0200181 return s;
182}
183
Dave Barachc3799992016-08-15 11:12:27 -0400184clib_error_t *
185unix_proc_file_contents (char *file, u8 ** result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186{
187 u8 *rv = 0;
188 uword pos;
189 int bytes, fd;
190
191 /* Unfortunately, stat(/proc/XXX) returns zero... */
192 fd = open (file, O_RDONLY);
193
194 if (fd < 0)
195 return clib_error_return_unix (0, "open `%s'", file);
196
Dave Barachc3799992016-08-15 11:12:27 -0400197 vec_validate (rv, 4095);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198 pos = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400199 while (1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200 {
Dave Barachc3799992016-08-15 11:12:27 -0400201 bytes = read (fd, rv + pos, 4096);
202 if (bytes < 0)
203 {
204 close (fd);
205 vec_free (rv);
206 return clib_error_return_unix (0, "read '%s'", file);
207 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208
Dave Barachc3799992016-08-15 11:12:27 -0400209 if (bytes == 0)
210 {
Damjan Marion8bea5892022-04-04 22:40:45 +0200211 vec_set_len (rv, pos);
Dave Barachc3799992016-08-15 11:12:27 -0400212 break;
213 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214 pos += bytes;
Dave Barachc3799992016-08-15 11:12:27 -0400215 vec_validate (rv, pos + 4095);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216 }
217 *result = rv;
218 close (fd);
219 return 0;
220}
221
222void os_panic (void) __attribute__ ((weak));
223
Damjan Marion4a251d02021-05-06 17:28:12 +0200224__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -0400225os_panic (void)
226{
227 abort ();
228}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229
230void os_exit (int) __attribute__ ((weak));
231
Dave Barachc3799992016-08-15 11:12:27 -0400232void
233os_exit (int code)
234{
235 exit (code);
236}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237
238void os_puts (u8 * string, uword string_length, uword is_error)
239 __attribute__ ((weak));
240
Dave Barachc3799992016-08-15 11:12:27 -0400241void
242os_puts (u8 * string, uword string_length, uword is_error)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243{
Damjan Marionf55f9b82017-05-10 21:06:28 +0200244 int cpu = os_get_thread_index ();
245 int nthreads = os_get_nthreads ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246 char buf[64];
247 int fd = is_error ? 2 : 1;
248 struct iovec iovs[2];
249 int n_iovs = 0;
250
Damjan Marionf55f9b82017-05-10 21:06:28 +0200251 if (nthreads > 1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252 {
Dave Barachc3799992016-08-15 11:12:27 -0400253 snprintf (buf, sizeof (buf), "%d: ", cpu);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254
255 iovs[n_iovs].iov_base = buf;
256 iovs[n_iovs].iov_len = strlen (buf);
257 n_iovs++;
258 }
259
260 iovs[n_iovs].iov_base = string;
261 iovs[n_iovs].iov_len = string_length;
262 n_iovs++;
263
264 if (writev (fd, iovs, n_iovs) < 0)
265 ;
266}
267
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200268__clib_export __clib_weak void
Dave Barachc3799992016-08-15 11:12:27 -0400269os_out_of_memory (void)
270{
271 os_panic ();
272}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200274__clib_export __clib_weak uword
Damjan Marionf55f9b82017-05-10 21:06:28 +0200275os_get_nthreads (void)
Dave Barachc3799992016-08-15 11:12:27 -0400276{
277 return 1;
278}
279
Damjan Marion4b661402024-02-29 16:14:27 +0100280__clib_export clib_bitmap_t *
281os_get_online_cpu_core_bitmap ()
282{
283#if __linux__
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000284 return clib_sysfs_read_bitmap ("/sys/devices/system/cpu/online");
Damjan Marion4b661402024-02-29 16:14:27 +0100285#else
286 return 0;
287#endif
288}
289
290__clib_export clib_bitmap_t *
Tom Jones2e87d942024-05-06 14:53:57 +0000291os_get_cpu_affinity_bitmap (int pid)
292{
293#if __linux
294 int index, ret;
295 cpu_set_t cpuset;
296 uword *affinity_cpus;
297
298 clib_bitmap_alloc (affinity_cpus, sizeof (cpu_set_t));
299 clib_bitmap_zero (affinity_cpus);
300
301 __CPU_ZERO_S (sizeof (cpu_set_t), &cpuset);
302
303 ret = sched_getaffinity (0, sizeof (cpu_set_t), &cpuset);
304
305 if (ret < 0)
306 {
307 clib_bitmap_free (affinity_cpus);
308 return 0;
309 }
310
311 for (index = 0; index < sizeof (cpu_set_t); index++)
312 if (__CPU_ISSET_S (index, sizeof (cpu_set_t), &cpuset))
313 clib_bitmap_set (affinity_cpus, index, 1);
314 return affinity_cpus;
315#elif defined(__FreeBSD__)
316 cpuset_t mask;
317 uword *r = NULL;
318
319 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");
Tom Jones2e87d942024-05-06 14:53:57 +0000340#elif defined(__FreeBSD__)
341 domainset_t domain;
342 uword *r = NULL;
343 int policy;
344
345 if (cpuset_getdomain (CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, -1,
346 sizeof (domain), &domain, &policy) != 0)
347 {
348 clib_bitmap_free (r);
349 return NULL;
350 }
351
352 for (int bit = 0; bit < CPU_SETSIZE; bit++)
353 clib_bitmap_set (r, bit, CPU_ISSET (bit, &domain));
354 return r;
Damjan Marion4b661402024-02-29 16:14:27 +0100355#else
356 return 0;
357#endif
358}
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000359__clib_export clib_bitmap_t *
360os_get_cpu_on_node_bitmap (int node)
361{
362#if __linux__
363 return clib_sysfs_read_bitmap ("/sys/devices/system/node/node%u/cpulist",
364 node);
365#else
366 return 0;
367#endif
368}
369
370__clib_export clib_bitmap_t *
371os_get_cpu_with_memory_bitmap ()
372{
373#if __linux__
374 return clib_sysfs_read_bitmap ("/sys/devices/system/node/has_memory");
375#else
376 return 0;
377#endif
378}
379
380__clib_export int
381os_get_cpu_phys_core_id (int cpu_id)
382{
383#if __linux
384 int core_id = -1;
385 clib_error_t *err;
386 u8 *p;
387
388 p =
389 format (0, "/sys/devices/system/cpu/cpu%u/topology/core_id%c", cpu_id, 0);
390 err = clib_sysfs_read ((char *) p, "%d", &core_id);
391 vec_free (p);
392 if (err)
393 {
394 clib_error_free (err);
395 return -1;
396 }
397 return core_id;
398#else
399 return -1;
400#endif
401}
Damjan Marion4b661402024-02-29 16:14:27 +0100402
Tom Jonesab479932024-04-24 10:30:20 +0000403__clib_export u8 *
404os_get_exec_path ()
405{
406 u8 *rv = 0;
407#ifdef __linux__
408 char tmp[PATH_MAX];
409 ssize_t sz = readlink ("/proc/self/exe", tmp, sizeof (tmp));
410
411 if (sz <= 0)
412 return 0;
413#else
414 char tmp[MAXPATHLEN];
415 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
416 size_t sz = MAXPATHLEN;
417
418 if (sysctl (mib, 4, tmp, &sz, NULL, 0) == -1)
419 return 0;
420#endif
421 vec_add (rv, tmp, sz);
422 return rv;
423}
424
Dave Barachc3799992016-08-15 11:12:27 -0400425/*
426 * fd.io coding-style-patch-verification: ON
427 *
428 * Local Variables:
429 * eval: (c-set-style "gnu")
430 * End:
431 */