udp: fix csum computation when offload disabled
[vpp.git] / src / vppinfra / unix-misc.c
1 /*
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
38 #ifndef _GNU_SOURCE
39 #define _GNU_SOURCE
40 #endif
41
42 #include <vppinfra/error.h>
43 #include <vppinfra/os.h>
44 #include <vppinfra/bitmap.h>
45 #include <vppinfra/unix.h>
46 #include <vppinfra/format.h>
47 #ifdef __linux__
48 #include <vppinfra/linux/sysfs.h>
49 #include <sched.h>
50 #elif defined(__FreeBSD__)
51 #define _WANT_FREEBSD_BITSET
52 #include <sys/cdefs.h>
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/cpuset.h>
56 #include <sys/domainset.h>
57 #include <sys/sysctl.h>
58 #endif
59
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 */
65 #include <limits.h>
66
67 __clib_export __thread uword __os_thread_index = 0;
68 __clib_export __thread uword __os_numa_index = 0;
69
70 clib_error_t *
71 clib_file_n_bytes (char *file, uword * result)
72 {
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
86 clib_error_t *
87 clib_file_read_contents (char *file, u8 * result, uword n_bytes)
88 {
89   int fd = -1;
90   uword n_done, n_left;
91   clib_error_t *error = 0;
92   u8 *v = result;
93
94   if ((fd = open (file, 0)) < 0)
95     return clib_error_return_unix (0, "open `%s'", file);
96
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     {
118       error =
119         clib_error_return (0,
120                            " `%s' expected to read %wd bytes; read only %wd",
121                            file, n_bytes, n_bytes - n_left);
122       goto done;
123     }
124
125 done:
126   close (fd);
127   return error;
128 }
129
130 __clib_export clib_error_t *
131 clib_file_contents (char *file, u8 ** result)
132 {
133   uword n_bytes;
134   clib_error_t *error = 0;
135   u8 *v;
136
137   if ((error = clib_file_n_bytes (file, &n_bytes)))
138     return error;
139
140   v = 0;
141   vec_resize (v, n_bytes);
142
143   error = clib_file_read_contents (file, v, n_bytes);
144
145   if (error)
146     vec_free (v);
147   else
148     *result = v;
149
150   return error;
151 }
152
153 __clib_export u8 *
154 clib_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
172   buffer[r] = 0;
173   p = buffer + r - 1;
174   while (p > buffer && p[-1] != '/')
175     p--;
176
177   while (p[0])
178     vec_add1 (s, p++[0]);
179
180   vec_add1 (s, 0);
181   return s;
182 }
183
184 clib_error_t *
185 unix_proc_file_contents (char *file, u8 ** result)
186 {
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
197   vec_validate (rv, 4095);
198   pos = 0;
199   while (1)
200     {
201       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         }
208
209       if (bytes == 0)
210         {
211           vec_set_len (rv, pos);
212           break;
213         }
214       pos += bytes;
215       vec_validate (rv, pos + 4095);
216     }
217   *result = rv;
218   close (fd);
219   return 0;
220 }
221
222 void os_panic (void) __attribute__ ((weak));
223
224 __clib_export void
225 os_panic (void)
226 {
227   abort ();
228 }
229
230 void os_exit (int) __attribute__ ((weak));
231
232 void
233 os_exit (int code)
234 {
235   exit (code);
236 }
237
238 void os_puts (u8 * string, uword string_length, uword is_error)
239   __attribute__ ((weak));
240
241 void
242 os_puts (u8 * string, uword string_length, uword is_error)
243 {
244   int cpu = os_get_thread_index ();
245   int nthreads = os_get_nthreads ();
246   char buf[64];
247   int fd = is_error ? 2 : 1;
248   struct iovec iovs[2];
249   int n_iovs = 0;
250
251   if (nthreads > 1)
252     {
253       snprintf (buf, sizeof (buf), "%d: ", cpu);
254
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
268 __clib_export __clib_weak void
269 os_out_of_memory (void)
270 {
271   os_panic ();
272 }
273
274 __clib_export __clib_weak uword
275 os_get_nthreads (void)
276 {
277   return 1;
278 }
279
280 __clib_export clib_bitmap_t *
281 os_get_online_cpu_core_bitmap ()
282 {
283 #if __linux__
284   return clib_sysfs_read_bitmap ("/sys/devices/system/cpu/online");
285 #else
286   return 0;
287 #endif
288 }
289
290 __clib_export clib_bitmap_t *
291 os_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 *
336 os_get_online_cpu_node_bitmap ()
337 {
338 #if __linux__
339   return clib_sysfs_read_bitmap ("/sys/devices/system/node/online");
340 #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;
355 #else
356   return 0;
357 #endif
358 }
359 __clib_export clib_bitmap_t *
360 os_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 *
371 os_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
381 os_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 }
402
403 __clib_export u8 *
404 os_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
425 /*
426  * fd.io coding-style-patch-verification: ON
427  *
428  * Local Variables:
429  * eval: (c-set-style "gnu")
430  * End:
431  */