back to topotato report
topotato coverage report
Current view: top level - lib - ntop.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 75 80 93.8 %
Date: 2023-11-16 17:19:14 Functions: 1 2 50.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: ISC
       2             : /*
       3             :  * optimized ntop, about 10x faster than libc versions [as of 2019]
       4             :  *
       5             :  * Copyright (c) 2019  David Lamparter, for NetDEF, Inc.
       6             :  */
       7             : 
       8             : #ifdef HAVE_CONFIG_H
       9             : #include "config.h"
      10             : #endif
      11             : 
      12             : #include <stdio.h>
      13             : #include <stdint.h>
      14             : #include <stdbool.h>
      15             : #include <string.h>
      16             : #include <sys/socket.h>
      17             : #include <netinet/in.h>
      18             : #include <arpa/inet.h>
      19             : 
      20             : #include "compiler.h"
      21             : 
      22             : #define pos (*posx)
      23             : 
      24             : static inline void putbyte(uint8_t bytex, char **posx)
      25             :         __attribute__((always_inline)) OPTIMIZE;
      26             : 
      27         708 : static inline void putbyte(uint8_t bytex, char **posx)
      28             : {
      29         708 :         bool zero = false;
      30         708 :         int byte = bytex, tmp, a, b;
      31             : 
      32         708 :         tmp = byte - 200;
      33         708 :         if (tmp >= 0) {
      34          79 :                 *pos++ = '2';
      35          79 :                 zero = true;
      36          79 :                 byte = tmp;
      37             :         } else {
      38         629 :                 tmp = byte - 100;
      39         629 :                 if (tmp >= 0) {
      40          79 :                         *pos++ = '1';
      41          79 :                         zero = true;
      42          79 :                         byte = tmp;
      43             :                 }
      44             :         }
      45             : 
      46             :         /* make sure the compiler knows the value range of "byte" */
      47         708 :         assume(byte < 100 && byte >= 0);
      48             : 
      49         708 :         b = byte % 10;
      50         708 :         a = byte / 10;
      51         708 :         if (a || zero) {
      52         316 :                 *pos++ = '0' + a;
      53         316 :                 *pos++ = '0' + b;
      54             :         } else
      55         392 :                 *pos++ = '0' + b;
      56             : }
      57             : 
      58             : static inline void puthex(uint16_t word, char **posx)
      59             :         __attribute__((always_inline)) OPTIMIZE;
      60             : 
      61         972 : static inline void puthex(uint16_t word, char **posx)
      62             : {
      63         972 :         const char *digits = "0123456789abcdef";
      64         972 :         if (word >= 0x1000)
      65         557 :                 *pos++ = digits[(word >> 12) & 0xf];
      66         972 :         if (word >= 0x100)
      67         678 :                 *pos++ = digits[(word >> 8) & 0xf];
      68         972 :         if (word >= 0x10)
      69         799 :                 *pos++ = digits[(word >> 4) & 0xf];
      70         972 :         *pos++ = digits[word & 0xf];
      71             : }
      72             : 
      73             : #undef pos
      74             : 
      75             : const char *frr_inet_ntop(int af, const void * restrict src,
      76             :                           char * restrict dst, socklen_t size)
      77             :         __attribute__((flatten)) OPTIMIZE;
      78             : 
      79         502 : const char *frr_inet_ntop(int af, const void * restrict src,
      80             :                           char * restrict dst, socklen_t size)
      81             : {
      82         502 :         const uint8_t *b = src;
      83             :         /* 8 * "abcd:" for IPv6
      84             :          * note: the IPv4-embedded IPv6 syntax is only used for ::A.B.C.D,
      85             :          * which isn't longer than 40 chars either.  even with ::ffff:A.B.C.D
      86             :          * it's shorter.
      87             :          */
      88         502 :         char buf[8 * 5], *o = buf;
      89         502 :         size_t best = 0, bestlen = 0, curlen = 0, i;
      90             : 
      91         502 :         switch (af) {
      92             :         case AF_INET:
      93         177 : inet4:
      94         177 :                 putbyte(b[0], &o);
      95         177 :                 *o++ = '.';
      96         177 :                 putbyte(b[1], &o);
      97         177 :                 *o++ = '.';
      98         177 :                 putbyte(b[2], &o);
      99         177 :                 *o++ = '.';
     100         177 :                 putbyte(b[3], &o);
     101         177 :                 *o++ = '\0';
     102         177 :                 break;
     103             :         case AF_INET6:
     104        2925 :                 for (i = 0; i < 8; i++) {
     105        2600 :                         if (b[i * 2] || b[i * 2 + 1]) {
     106         972 :                                 if (curlen && curlen > bestlen) {
     107         143 :                                         best = i - curlen;
     108         143 :                                         bestlen = curlen;
     109             :                                 }
     110         972 :                                 curlen = 0;
     111         972 :                                 continue;
     112             :                         }
     113        1628 :                         curlen++;
     114             :                 }
     115         325 :                 if (curlen && curlen > bestlen) {
     116         182 :                         best = i - curlen;
     117         182 :                         bestlen = curlen;
     118             :                 }
     119             :                 /* do we want ::ffff:A.B.C.D? */
     120         325 :                 if (best == 0 && bestlen == 6) {
     121           0 :                         *o++ = ':';
     122           0 :                         *o++ = ':';
     123           0 :                         b += 12;
     124           0 :                         goto inet4;
     125             :                 }
     126         325 :                 if (bestlen == 1)
     127           0 :                         bestlen = 0;
     128             : 
     129        2925 :                 for (i = 0; i < 8; i++) {
     130        2600 :                         if (bestlen && i == best) {
     131         325 :                                 if (i == 0)
     132          10 :                                         *o++ = ':';
     133         325 :                                 *o++ = ':';
     134         325 :                                 continue;
     135             :                         }
     136        2275 :                         if (i > best && i < best + bestlen) {
     137        1303 :                                 continue;
     138             :                         }
     139         972 :                         puthex((b[i * 2] << 8) | b[i * 2 + 1], &o);
     140             : 
     141         972 :                         if (i < 7)
     142         829 :                                 *o++ = ':';
     143             :                 }
     144         325 :                 *o++ = '\0';
     145         325 :                 break;
     146             :         default:
     147             :                 return NULL;
     148             :         }
     149             : 
     150         502 :         i = o - buf;
     151         502 :         if (i > size)
     152             :                 return NULL;
     153             :         /* compiler might inline memcpy if it knows the length is short,
     154             :          * although neither gcc nor clang actually do this currently [2019]
     155             :          */
     156         502 :         assume(i <= 8 * 5);
     157         502 :         memcpy(dst, buf, i);
     158         502 :         return dst;
     159             : }
     160             : 
     161             : #if !defined(INET_NTOP_NO_OVERRIDE)
     162             : /* we want to override libc inet_ntop, but make sure it shows up in backtraces
     163             :  * as frr_inet_ntop (to avoid confusion while debugging)
     164             :  */
     165             : const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
     166             :         __attribute__((alias ("frr_inet_ntop")));
     167             : #endif

Generated by: LCOV version v1.16-topotato