]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib: add optimized inet_ntop()
authorDavid Lamparter <equinox@diac24.net>
Thu, 6 Jun 2019 17:10:29 +0000 (19:10 +0200)
committerDavid Lamparter <equinox@diac24.net>
Thu, 6 Jun 2019 18:59:50 +0000 (20:59 +0200)
This commit is brought to you by: "Manuel - Gas Gas Gas" (Initial D)

Signed-off-by: David Lamparter <equinox@diac24.net>
lib/ntop.c [new file with mode: 0644]
lib/subdir.am

diff --git a/lib/ntop.c b/lib/ntop.c
new file mode 100644 (file)
index 0000000..5500f98
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * optimized ntop, about 10x faster than libc versions [as of 2019]
+ *
+ * Copyright (c) 2019  David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "compiler.h"
+
+#define pos (*posx)
+
+static inline void putbyte(uint8_t bytex, char **posx)
+       __attribute__((always_inline)) OPTIMIZE;
+
+static inline void putbyte(uint8_t bytex, char **posx)
+{
+       bool zero = false;
+       int byte = bytex, tmp, a, b;
+
+       if ((tmp = byte - 200) >= 0) {
+               *pos++ = '2';
+               zero = true;
+               byte = tmp;
+       } else if ((tmp = byte - 100) >= 0) {
+               *pos++ = '1';
+               zero = true;
+               byte = tmp;
+       }
+
+       /* make sure the compiler knows the value range of "byte" */
+       assume(byte < 100 && byte >= 0);
+
+       b = byte % 10;
+       a = byte / 10;
+       if (a || zero) {
+               *pos++ = '0' + a;
+               *pos++ = '0' + b;
+       } else
+               *pos++ = '0' + b;
+}
+
+static inline void puthex(uint16_t word, char **posx)
+       __attribute__((always_inline)) OPTIMIZE;
+
+static inline void puthex(uint16_t word, char **posx)
+{
+       const char *digits = "0123456789abcdef";
+       if (word >= 0x1000)
+               *pos++ = digits[(word >> 12) & 0xf];
+       if (word >= 0x100)
+               *pos++ = digits[(word >> 8) & 0xf];
+       if (word >= 0x10)
+               *pos++ = digits[(word >> 4) & 0xf];
+       *pos++ = digits[word & 0xf];
+}
+
+#undef pos
+
+const char *frr_inet_ntop(int af, const void * restrict src,
+                         char * restrict dst, socklen_t size)
+       __attribute__((flatten)) DSO_SELF OPTIMIZE;
+
+const char *frr_inet_ntop(int af, const void * restrict src,
+                         char * restrict dst, socklen_t size)
+{
+       const uint8_t *b = src;
+       /* 8 * "abcd:" for IPv6
+        * note: the IPv4-embedded IPv6 syntax is only used for ::A.B.C.D,
+        * which isn't longer than 40 chars either.  even with ::ffff:A.B.C.D
+        * it's shorter.
+        */
+       char buf[8 * 5], *o = buf;
+       size_t best = 0, bestlen = 0, curlen = 0, i;
+
+       switch (af) {
+       case AF_INET:
+inet4:
+               putbyte(b[0], &o);
+               *o++ = '.';
+               putbyte(b[1], &o);
+               *o++ = '.';
+               putbyte(b[2], &o);
+               *o++ = '.';
+               putbyte(b[3], &o);
+               *o++ = '\0';
+               break;
+       case AF_INET6:
+               for (i = 0; i < 8; i++) {
+                       if (b[i * 2] || b[i * 2 + 1]) {
+                               if (curlen && curlen > bestlen) {
+                                       best = i - curlen;
+                                       bestlen = curlen;
+                               }
+                               curlen = 0;
+                               continue;
+                       }
+                       curlen++;
+               }
+               if (curlen && curlen > bestlen) {
+                       best = i - curlen;
+                       bestlen = curlen;
+               }
+               /* do we want ::ffff:A.B.C.D? */
+               if (best == 0 && bestlen == 6) {
+                       *o++ = ':';
+                       *o++ = ':';
+                       b += 12;
+                       goto inet4;
+               }
+               if (bestlen == 1)
+                       bestlen = 0;
+
+               for (i = 0; i < 8; i++) {
+                       if (bestlen && i == best) {
+                               if (i == 0)
+                                       *o++ = ':';
+                               *o++ = ':';
+                               continue;
+                       }
+                       if (i > best && i < best + bestlen) {
+                               continue;
+                       }
+                       puthex((b[i * 2] << 8) | b[i * 2 + 1], &o);
+
+                       if (i < 7)
+                               *o++ = ':';
+               }
+               *o++ = '\0';
+               break;
+       default:
+               return NULL;
+       }
+
+       i = o - buf;
+       if (i > size)
+               return NULL;
+       /* compiler might inline memcpy if it knows the length is short,
+        * although neither gcc nor clang actually do this currently [2019]
+        */
+       assume(i <= 8 * 5);
+       memcpy(dst, buf, i);
+       return dst;
+}
+
+/* we want to override libc inet_ntop, but make sure it shows up in backtraces
+ * as frr_inet_ntop (to avoid confusion while debugging)
+ */
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
+       __attribute__((alias ("frr_inet_ntop"))) DSO_SELF;
index 50ff1feeccf708f52640ba678e2500eb136fbdd1..4e6adced7449792174306d6462968a0cb6eb4a59 100644 (file)
@@ -56,6 +56,7 @@ lib_libfrr_la_SOURCES = \
        lib/northbound.c \
        lib/northbound_cli.c \
        lib/northbound_db.c \
+       lib/ntop.c \
        lib/openbsd-tree.c \
        lib/pid_output.c \
        lib/plist.c \