]>
Commit | Line | Data |
---|---|---|
e128c002 DL |
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 | static inline void putbyte(uint8_t bytex, char **posx) | |
39 | { | |
40 | bool zero = false; | |
41 | int byte = bytex, tmp, a, b; | |
42 | ||
0e2d7076 DA |
43 | tmp = byte - 200; |
44 | if (tmp >= 0) { | |
e128c002 DL |
45 | *pos++ = '2'; |
46 | zero = true; | |
47 | byte = tmp; | |
0e2d7076 DA |
48 | } else { |
49 | tmp = byte - 100; | |
50 | if (tmp >= 0) { | |
51 | *pos++ = '1'; | |
52 | zero = true; | |
53 | byte = tmp; | |
54 | } | |
e128c002 DL |
55 | } |
56 | ||
57 | /* make sure the compiler knows the value range of "byte" */ | |
58 | assume(byte < 100 && byte >= 0); | |
59 | ||
60 | b = byte % 10; | |
61 | a = byte / 10; | |
62 | if (a || zero) { | |
63 | *pos++ = '0' + a; | |
64 | *pos++ = '0' + b; | |
65 | } else | |
66 | *pos++ = '0' + b; | |
67 | } | |
68 | ||
69 | static inline void puthex(uint16_t word, char **posx) | |
70 | __attribute__((always_inline)) OPTIMIZE; | |
71 | ||
72 | static inline void puthex(uint16_t word, char **posx) | |
73 | { | |
74 | const char *digits = "0123456789abcdef"; | |
75 | if (word >= 0x1000) | |
76 | *pos++ = digits[(word >> 12) & 0xf]; | |
77 | if (word >= 0x100) | |
78 | *pos++ = digits[(word >> 8) & 0xf]; | |
79 | if (word >= 0x10) | |
80 | *pos++ = digits[(word >> 4) & 0xf]; | |
81 | *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) | |
866f6e40 | 88 | __attribute__((flatten)) OPTIMIZE; |
e128c002 DL |
89 | |
90 | const char *frr_inet_ntop(int af, const void * restrict src, | |
91 | char * restrict dst, socklen_t size) | |
92 | { | |
93 | 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 | char buf[8 * 5], *o = buf; | |
100 | size_t best = 0, bestlen = 0, curlen = 0, i; | |
101 | ||
102 | switch (af) { | |
103 | case AF_INET: | |
104 | inet4: | |
105 | putbyte(b[0], &o); | |
106 | *o++ = '.'; | |
107 | putbyte(b[1], &o); | |
108 | *o++ = '.'; | |
109 | putbyte(b[2], &o); | |
110 | *o++ = '.'; | |
111 | putbyte(b[3], &o); | |
112 | *o++ = '\0'; | |
113 | break; | |
114 | case AF_INET6: | |
115 | for (i = 0; i < 8; i++) { | |
116 | if (b[i * 2] || b[i * 2 + 1]) { | |
117 | if (curlen && curlen > bestlen) { | |
118 | best = i - curlen; | |
119 | bestlen = curlen; | |
120 | } | |
121 | curlen = 0; | |
122 | continue; | |
123 | } | |
124 | curlen++; | |
125 | } | |
126 | if (curlen && curlen > bestlen) { | |
127 | best = i - curlen; | |
128 | bestlen = curlen; | |
129 | } | |
130 | /* do we want ::ffff:A.B.C.D? */ | |
131 | if (best == 0 && bestlen == 6) { | |
132 | *o++ = ':'; | |
133 | *o++ = ':'; | |
134 | b += 12; | |
135 | goto inet4; | |
136 | } | |
137 | if (bestlen == 1) | |
138 | bestlen = 0; | |
139 | ||
140 | for (i = 0; i < 8; i++) { | |
141 | if (bestlen && i == best) { | |
142 | if (i == 0) | |
143 | *o++ = ':'; | |
144 | *o++ = ':'; | |
145 | continue; | |
146 | } | |
147 | if (i > best && i < best + bestlen) { | |
148 | continue; | |
149 | } | |
150 | puthex((b[i * 2] << 8) | b[i * 2 + 1], &o); | |
151 | ||
152 | if (i < 7) | |
153 | *o++ = ':'; | |
154 | } | |
155 | *o++ = '\0'; | |
156 | break; | |
157 | default: | |
158 | return NULL; | |
159 | } | |
160 | ||
161 | i = o - buf; | |
162 | 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 | assume(i <= 8 * 5); | |
168 | memcpy(dst, buf, i); | |
169 | return dst; | |
170 | } | |
171 | ||
8d80a842 | 172 | #if !defined(INET_NTOP_NO_OVERRIDE) && !defined(__APPLE__) |
e128c002 DL |
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) | |
866f6e40 | 177 | __attribute__((alias ("frr_inet_ntop"))); |
874035be | 178 | #endif |