back to topotato report
topotato coverage report
Current view: top level - lib - ntop.c (source / functions) Hit Total Coverage
Test: test_ospf6_vlink.py::VirtualLinkBasic Lines: 75 80 93.8 %
Date: 2023-02-16 02:06:43 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /*
       2             :  * optimized ntop, about 10x faster than libc versions [as of 2019]
       3             :  *
       4             :  * Copyright (c) 2019  David Lamparter, for NetDEF, Inc.
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : #ifdef HAVE_CONFIG_H
      20             : #include "config.h"
      21             : #endif
      22             : 
      23             : #include <stdio.h>
      24             : #include <stdint.h>
      25             : #include <stdbool.h>
      26             : #include <string.h>
      27             : #include <sys/socket.h>
      28             : #include <netinet/in.h>
      29             : #include <arpa/inet.h>
      30             : 
      31             : #include "compiler.h"
      32             : 
      33             : #define pos (*posx)
      34             : 
      35             : static inline void putbyte(uint8_t bytex, char **posx)
      36             :         __attribute__((always_inline)) OPTIMIZE;
      37             : 
      38       41544 : static inline void putbyte(uint8_t bytex, char **posx)
      39             : {
      40       41544 :         bool zero = false;
      41       41544 :         int byte = bytex, tmp, a, b;
      42             : 
      43       41544 :         tmp = byte - 200;
      44       41544 :         if (tmp >= 0) {
      45        5864 :                 *pos++ = '2';
      46        5864 :                 zero = true;
      47        5864 :                 byte = tmp;
      48             :         } else {
      49       35680 :                 tmp = byte - 100;
      50       35680 :                 if (tmp >= 0) {
      51          15 :                         *pos++ = '1';
      52          15 :                         zero = true;
      53          15 :                         byte = tmp;
      54             :                 }
      55             :         }
      56             : 
      57             :         /* make sure the compiler knows the value range of "byte" */
      58       41544 :         assume(byte < 100 && byte >= 0);
      59             : 
      60       41544 :         b = byte % 10;
      61       41544 :         a = byte / 10;
      62       41544 :         if (a || zero) {
      63       11818 :                 *pos++ = '0' + a;
      64       11818 :                 *pos++ = '0' + b;
      65             :         } else
      66       29726 :                 *pos++ = '0' + b;
      67             : }
      68             : 
      69             : static inline void puthex(uint16_t word, char **posx)
      70             :         __attribute__((always_inline)) OPTIMIZE;
      71             : 
      72        9067 : static inline void puthex(uint16_t word, char **posx)
      73             : {
      74        9067 :         const char *digits = "0123456789abcdef";
      75        9067 :         if (word >= 0x1000)
      76        2955 :                 *pos++ = digits[(word >> 12) & 0xf];
      77        9067 :         if (word >= 0x100)
      78        4855 :                 *pos++ = digits[(word >> 8) & 0xf];
      79        9067 :         if (word >= 0x10)
      80        5209 :                 *pos++ = digits[(word >> 4) & 0xf];
      81        9067 :         *pos++ = digits[word & 0xf];
      82             : }
      83             : 
      84             : #undef pos
      85             : 
      86             : const char *frr_inet_ntop(int af, const void * restrict src,
      87             :                           char * restrict dst, socklen_t size)
      88             :         __attribute__((flatten)) OPTIMIZE;
      89             : 
      90       13143 : const char *frr_inet_ntop(int af, const void * restrict src,
      91             :                           char * restrict dst, socklen_t size)
      92             : {
      93       13143 :         const uint8_t *b = src;
      94             :         /* 8 * "abcd:" for IPv6
      95             :          * note: the IPv4-embedded IPv6 syntax is only used for ::A.B.C.D,
      96             :          * which isn't longer than 40 chars either.  even with ::ffff:A.B.C.D
      97             :          * it's shorter.
      98             :          */
      99       13143 :         char buf[8 * 5], *o = buf;
     100       13143 :         size_t best = 0, bestlen = 0, curlen = 0, i;
     101             : 
     102       13143 :         switch (af) {
     103             :         case AF_INET:
     104       10386 : inet4:
     105       10386 :                 putbyte(b[0], &o);
     106       10386 :                 *o++ = '.';
     107       10386 :                 putbyte(b[1], &o);
     108       10386 :                 *o++ = '.';
     109       10386 :                 putbyte(b[2], &o);
     110       10386 :                 *o++ = '.';
     111       10386 :                 putbyte(b[3], &o);
     112       10386 :                 *o++ = '\0';
     113       10386 :                 break;
     114             :         case AF_INET6:
     115       24813 :                 for (i = 0; i < 8; i++) {
     116       22056 :                         if (b[i * 2] || b[i * 2 + 1]) {
     117        8393 :                                 if (curlen && curlen > bestlen) {
     118        1189 :                                         best = i - curlen;
     119        1189 :                                         bestlen = curlen;
     120             :                                 }
     121        8393 :                                 curlen = 0;
     122        8393 :                                 continue;
     123             :                         }
     124       13663 :                         curlen++;
     125             :                 }
     126        2757 :                 if (curlen && curlen > bestlen) {
     127        2242 :                         best = i - curlen;
     128        2242 :                         bestlen = curlen;
     129             :                 }
     130             :                 /* do we want ::ffff:A.B.C.D? */
     131        2757 :                 if (best == 0 && bestlen == 6) {
     132           0 :                         *o++ = ':';
     133           0 :                         *o++ = ':';
     134           0 :                         b += 12;
     135           0 :                         goto inet4;
     136             :                 }
     137        2757 :                 if (bestlen == 1)
     138           0 :                         bestlen = 0;
     139             : 
     140       24813 :                 for (i = 0; i < 8; i++) {
     141       22056 :                         if (bestlen && i == best) {
     142        2757 :                                 if (i == 0)
     143          16 :                                         *o++ = ':';
     144        2757 :                                 *o++ = ':';
     145        2757 :                                 continue;
     146             :                         }
     147       19299 :                         if (i > best && i < best + bestlen) {
     148       10232 :                                 continue;
     149             :                         }
     150        9067 :                         puthex((b[i * 2] << 8) | b[i * 2 + 1], &o);
     151             : 
     152        9067 :                         if (i < 7)
     153        8552 :                                 *o++ = ':';
     154             :                 }
     155        2757 :                 *o++ = '\0';
     156        2757 :                 break;
     157             :         default:
     158             :                 return NULL;
     159             :         }
     160             : 
     161       13143 :         i = o - buf;
     162       13143 :         if (i > size)
     163             :                 return NULL;
     164             :         /* compiler might inline memcpy if it knows the length is short,
     165             :          * although neither gcc nor clang actually do this currently [2019]
     166             :          */
     167       13143 :         assume(i <= 8 * 5);
     168       13143 :         memcpy(dst, buf, i);
     169       13143 :         return dst;
     170             : }
     171             : 
     172             : #if !defined(INET_NTOP_NO_OVERRIDE) && !defined(__APPLE__)
     173             : /* we want to override libc inet_ntop, but make sure it shows up in backtraces
     174             :  * as frr_inet_ntop (to avoid confusion while debugging)
     175             :  */
     176             : const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
     177             :         __attribute__((alias ("frr_inet_ntop")));
     178             : #endif

Generated by: LCOV version v1.16-topotato