blob: 88a56d88afc13d07bc5154beedd8c58891e645d1 [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
Benoît Ganne448f08b2024-06-17 15:32:12 +0200222__clib_export __clib_weak void
Dave Barachc3799992016-08-15 11:12:27 -0400223os_panic (void)
224{
225 abort ();
226}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227
Benoît Ganne448f08b2024-06-17 15:32:12 +0200228__clib_export __clib_weak void
Dave Barachc3799992016-08-15 11:12:27 -0400229os_exit (int code)
230{
231 exit (code);
232}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233
Benoît Ganne448f08b2024-06-17 15:32:12 +0200234__clib_export __clib_weak void
235os_puts (u8 *string, uword string_length, uword is_error)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236{
Damjan Marionf55f9b82017-05-10 21:06:28 +0200237 int cpu = os_get_thread_index ();
238 int nthreads = os_get_nthreads ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 char buf[64];
240 int fd = is_error ? 2 : 1;
241 struct iovec iovs[2];
242 int n_iovs = 0;
243
Damjan Marionf55f9b82017-05-10 21:06:28 +0200244 if (nthreads > 1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 {
Dave Barachc3799992016-08-15 11:12:27 -0400246 snprintf (buf, sizeof (buf), "%d: ", cpu);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247
248 iovs[n_iovs].iov_base = buf;
249 iovs[n_iovs].iov_len = strlen (buf);
250 n_iovs++;
251 }
252
253 iovs[n_iovs].iov_base = string;
254 iovs[n_iovs].iov_len = string_length;
255 n_iovs++;
256
257 if (writev (fd, iovs, n_iovs) < 0)
258 ;
259}
260
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200261__clib_export __clib_weak void
Dave Barachc3799992016-08-15 11:12:27 -0400262os_out_of_memory (void)
263{
264 os_panic ();
265}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200267__clib_export __clib_weak uword
Damjan Marionf55f9b82017-05-10 21:06:28 +0200268os_get_nthreads (void)
Dave Barachc3799992016-08-15 11:12:27 -0400269{
270 return 1;
271}
272
Damjan Marion4b661402024-02-29 16:14:27 +0100273__clib_export clib_bitmap_t *
274os_get_online_cpu_core_bitmap ()
275{
276#if __linux__
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000277 return clib_sysfs_read_bitmap ("/sys/devices/system/cpu/online");
Damjan Marion4b661402024-02-29 16:14:27 +0100278#else
279 return 0;
280#endif
281}
282
283__clib_export clib_bitmap_t *
Tom Jones2e87d942024-05-06 14:53:57 +0000284os_get_cpu_affinity_bitmap (int pid)
285{
286#if __linux
287 int index, ret;
288 cpu_set_t cpuset;
289 uword *affinity_cpus;
290
291 clib_bitmap_alloc (affinity_cpus, sizeof (cpu_set_t));
292 clib_bitmap_zero (affinity_cpus);
293
Renato Botelho do Couto7f3c2172024-06-21 14:00:10 +0000294 CPU_ZERO_S (sizeof (cpu_set_t), &cpuset);
Tom Jones2e87d942024-05-06 14:53:57 +0000295
296 ret = sched_getaffinity (0, sizeof (cpu_set_t), &cpuset);
297
298 if (ret < 0)
299 {
300 clib_bitmap_free (affinity_cpus);
301 return 0;
302 }
303
304 for (index = 0; index < sizeof (cpu_set_t); index++)
Renato Botelho do Couto7f3c2172024-06-21 14:00:10 +0000305 if (CPU_ISSET_S (index, sizeof (cpu_set_t), &cpuset))
Tom Jones2e87d942024-05-06 14:53:57 +0000306 clib_bitmap_set (affinity_cpus, index, 1);
307 return affinity_cpus;
308#elif defined(__FreeBSD__)
309 cpuset_t mask;
310 uword *r = NULL;
311
312 if (cpuset_getaffinity (CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, -1,
313 sizeof (mask), &mask) != 0)
314 {
315 clib_bitmap_free (r);
316 return NULL;
317 }
318
319 for (int bit = 0; bit < CPU_SETSIZE; bit++)
320 clib_bitmap_set (r, bit, CPU_ISSET (bit, &mask));
321
322 return r;
323#else
324 return NULL;
325#endif
326}
327
328__clib_export clib_bitmap_t *
Damjan Marion4b661402024-02-29 16:14:27 +0100329os_get_online_cpu_node_bitmap ()
330{
331#if __linux__
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000332 return clib_sysfs_read_bitmap ("/sys/devices/system/node/online");
Tom Jones2e87d942024-05-06 14:53:57 +0000333#elif defined(__FreeBSD__)
334 domainset_t domain;
335 uword *r = NULL;
336 int policy;
337
338 if (cpuset_getdomain (CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, -1,
339 sizeof (domain), &domain, &policy) != 0)
340 {
341 clib_bitmap_free (r);
342 return NULL;
343 }
344
345 for (int bit = 0; bit < CPU_SETSIZE; bit++)
346 clib_bitmap_set (r, bit, CPU_ISSET (bit, &domain));
347 return r;
Damjan Marion4b661402024-02-29 16:14:27 +0100348#else
349 return 0;
350#endif
351}
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000352__clib_export clib_bitmap_t *
353os_get_cpu_on_node_bitmap (int node)
354{
355#if __linux__
356 return clib_sysfs_read_bitmap ("/sys/devices/system/node/node%u/cpulist",
357 node);
358#else
359 return 0;
360#endif
361}
362
363__clib_export clib_bitmap_t *
364os_get_cpu_with_memory_bitmap ()
365{
366#if __linux__
367 return clib_sysfs_read_bitmap ("/sys/devices/system/node/has_memory");
368#else
369 return 0;
370#endif
371}
372
373__clib_export int
374os_get_cpu_phys_core_id (int cpu_id)
375{
376#if __linux
377 int core_id = -1;
378 clib_error_t *err;
379 u8 *p;
380
381 p =
382 format (0, "/sys/devices/system/cpu/cpu%u/topology/core_id%c", cpu_id, 0);
383 err = clib_sysfs_read ((char *) p, "%d", &core_id);
384 vec_free (p);
385 if (err)
386 {
387 clib_error_free (err);
388 return -1;
389 }
390 return core_id;
391#else
392 return -1;
393#endif
394}
Damjan Marion4b661402024-02-29 16:14:27 +0100395
Tom Jonesab479932024-04-24 10:30:20 +0000396__clib_export u8 *
397os_get_exec_path ()
398{
399 u8 *rv = 0;
400#ifdef __linux__
401 char tmp[PATH_MAX];
402 ssize_t sz = readlink ("/proc/self/exe", tmp, sizeof (tmp));
403
404 if (sz <= 0)
405 return 0;
406#else
407 char tmp[MAXPATHLEN];
408 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
409 size_t sz = MAXPATHLEN;
410
411 if (sysctl (mib, 4, tmp, &sz, NULL, 0) == -1)
412 return 0;
413#endif
414 vec_add (rv, tmp, sz);
415 return rv;
416}
417
Dave Barachc3799992016-08-15 11:12:27 -0400418/*
419 * fd.io coding-style-patch-verification: ON
420 *
421 * Local Variables:
422 * eval: (c-set-style "gnu")
423 * End:
424 */