core: move nfd-specific files to daemon/

Refs: #4922
Change-Id: I2243dbb87c63f9cbaf7d7051d7a0d4bca2f9fdb5
diff --git a/daemon/common/city-hash.cpp b/daemon/common/city-hash.cpp
new file mode 100644
index 0000000..b8a7791
--- /dev/null
+++ b/daemon/common/city-hash.cpp
@@ -0,0 +1,650 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// This file provides CityHash64() and related functions.
+//
+// It's probably possible to create even faster hash functions by
+// writing a program that systematically explores some of the space of
+// possible hash functions, by using SIMD instructions, or by
+// compromising on hash quality.
+
+//#include "config.h"
+#include "city-hash.hpp"
+#include <algorithm>
+#include <string.h>  // for memcpy and memset
+
+using namespace std;
+
+
+static uint64 UNALIGNED_LOAD64(const char *p) {
+  uint64 result;
+  memcpy(&result, p, sizeof(result));
+  return result;
+}
+
+static uint32 UNALIGNED_LOAD32(const char *p) {
+  uint32 result;
+  memcpy(&result, p, sizeof(result));
+  return result;
+}
+
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+#define bswap_32(x) _byteswap_ulong(x)
+#define bswap_64(x) _byteswap_uint64(x)
+
+#elif defined(__APPLE__)
+
+// Mac OS X / Darwin features
+#include <libkern/OSByteOrder.h>
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+
+#elif defined(__NetBSD__)
+
+#include <sys/types.h>
+#include <machine/bswap.h>
+#if defined(__BSWAP_RENAME) && !defined(__bswap_32)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#endif
+
+
+#elif defined(__FreeBSD__)
+
+// Based on https://code.google.com/p/freebsd/source/browse/sys/ofed/include/byteswap.h?spec=svn38a8350a629d959c8c5509221cd07ffb891b5a77&r=38a8350a629d959c8c5509221cd07ffb891b5a77
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#define bswap_16(x) bswap16(x)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+
+#else
+
+#include <byteswap.h>
+
+#endif
+
+#ifdef WORDS_BIGENDIAN
+#define uint32_in_expected_order(x) (bswap_32(x))
+#define uint64_in_expected_order(x) (bswap_64(x))
+#else
+#define uint32_in_expected_order(x) (x)
+#define uint64_in_expected_order(x) (x)
+#endif
+
+#if !defined(LIKELY)
+#if HAVE_BUILTIN_EXPECT
+#define LIKELY(x) (__builtin_expect(!!(x), 1))
+#else
+#define LIKELY(x) (x)
+#endif
+#endif
+
+static uint64 Fetch64(const char *p) {
+  return uint64_in_expected_order(UNALIGNED_LOAD64(p));
+}
+
+static uint32 Fetch32(const char *p) {
+  return uint32_in_expected_order(UNALIGNED_LOAD32(p));
+}
+
+// Some primes between 2^63 and 2^64 for various uses.
+static const uint64 k0 = 0xc3a5c85c97cb3127ULL;
+static const uint64 k1 = 0xb492b66fbe98f273ULL;
+static const uint64 k2 = 0x9ae16a3b2f90404fULL;
+
+// Magic numbers for 32-bit hashing.  Copied from Murmur3.
+static const uint32_t c1 = 0xcc9e2d51;
+static const uint32_t c2 = 0x1b873593;
+
+// A 32-bit to 32-bit integer hash copied from Murmur3.
+static uint32 fmix(uint32 h)
+{
+  h ^= h >> 16;
+  h *= 0x85ebca6b;
+  h ^= h >> 13;
+  h *= 0xc2b2ae35;
+  h ^= h >> 16;
+  return h;
+}
+
+static uint32 Rotate32(uint32 val, int shift) {
+  // Avoid shifting by 32: doing so yields an undefined result.
+  return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
+}
+
+#undef PERMUTE3
+#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0)
+
+static uint32 Mur(uint32 a, uint32 h) {
+  // Helper from Murmur3 for combining two 32-bit values.
+  a *= c1;
+  a = Rotate32(a, 17);
+  a *= c2;
+  h ^= a;
+  h = Rotate32(h, 19);
+  return h * 5 + 0xe6546b64;
+}
+
+static uint32 Hash32Len13to24(const char *s, size_t len) {
+  uint32 a = Fetch32(s - 4 + (len >> 1));
+  uint32 b = Fetch32(s + 4);
+  uint32 c = Fetch32(s + len - 8);
+  uint32 d = Fetch32(s + (len >> 1));
+  uint32 e = Fetch32(s);
+  uint32 f = Fetch32(s + len - 4);
+  uint32 h = len;
+
+  return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h)))))));
+}
+
+static uint32 Hash32Len0to4(const char *s, size_t len) {
+  uint32 b = 0;
+  uint32 c = 9;
+  for (size_t i = 0; i < len; i++) {
+    signed char v = s[i];
+    b = b * c1 + v;
+    c ^= b;
+  }
+  return fmix(Mur(b, Mur(len, c)));
+}
+
+static uint32 Hash32Len5to12(const char *s, size_t len) {
+  uint32 a = len, b = len * 5, c = 9, d = b;
+  a += Fetch32(s);
+  b += Fetch32(s + len - 4);
+  c += Fetch32(s + ((len >> 1) & 4));
+  return fmix(Mur(c, Mur(b, Mur(a, d))));
+}
+
+uint32 CityHash32(const char *s, size_t len) {
+  if (len <= 24) {
+    return len <= 12 ?
+        (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) :
+        Hash32Len13to24(s, len);
+  }
+
+  // len > 24
+  uint32 h = len, g = c1 * len, f = g;
+  uint32 a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2;
+  uint32 a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2;
+  uint32 a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2;
+  uint32 a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2;
+  uint32 a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2;
+  h ^= a0;
+  h = Rotate32(h, 19);
+  h = h * 5 + 0xe6546b64;
+  h ^= a2;
+  h = Rotate32(h, 19);
+  h = h * 5 + 0xe6546b64;
+  g ^= a1;
+  g = Rotate32(g, 19);
+  g = g * 5 + 0xe6546b64;
+  g ^= a3;
+  g = Rotate32(g, 19);
+  g = g * 5 + 0xe6546b64;
+  f += a4;
+  f = Rotate32(f, 19);
+  f = f * 5 + 0xe6546b64;
+  size_t iters = (len - 1) / 20;
+  do {
+    uint32 a0 = Rotate32(Fetch32(s) * c1, 17) * c2;
+    uint32 a1 = Fetch32(s + 4);
+    uint32 a2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2;
+    uint32 a3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2;
+    uint32 a4 = Fetch32(s + 16);
+    h ^= a0;
+    h = Rotate32(h, 18);
+    h = h * 5 + 0xe6546b64;
+    f += a1;
+    f = Rotate32(f, 19);
+    f = f * c1;
+    g += a2;
+    g = Rotate32(g, 18);
+    g = g * 5 + 0xe6546b64;
+    h ^= a3 + a1;
+    h = Rotate32(h, 19);
+    h = h * 5 + 0xe6546b64;
+    g ^= a4;
+    g = bswap_32(g) * 5;
+    h += a4 * 5;
+    h = bswap_32(h);
+    f += a0;
+    PERMUTE3(f, h, g);
+    s += 20;
+  } while (--iters != 0);
+  g = Rotate32(g, 11) * c1;
+  g = Rotate32(g, 17) * c1;
+  f = Rotate32(f, 11) * c1;
+  f = Rotate32(f, 17) * c1;
+  h = Rotate32(h + g, 19);
+  h = h * 5 + 0xe6546b64;
+  h = Rotate32(h, 17) * c1;
+  h = Rotate32(h + f, 19);
+  h = h * 5 + 0xe6546b64;
+  h = Rotate32(h, 17) * c1;
+  return h;
+}
+
+// Bitwise right rotate.  Normally this will compile to a single
+// instruction, especially if the shift is a manifest constant.
+static uint64 Rotate(uint64 val, int shift) {
+  // Avoid shifting by 64: doing so yields an undefined result.
+  return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
+}
+
+static uint64 ShiftMix(uint64 val) {
+  return val ^ (val >> 47);
+}
+
+static uint64 HashLen16(uint64 u, uint64 v) {
+  return Hash128to64(uint128(u, v));
+}
+
+static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
+  // Murmur-inspired hashing.
+  uint64 a = (u ^ v) * mul;
+  a ^= (a >> 47);
+  uint64 b = (v ^ a) * mul;
+  b ^= (b >> 47);
+  b *= mul;
+  return b;
+}
+
+static uint64 HashLen0to16(const char *s, size_t len) {
+  if (len >= 8) {
+    uint64 mul = k2 + len * 2;
+    uint64 a = Fetch64(s) + k2;
+    uint64 b = Fetch64(s + len - 8);
+    uint64 c = Rotate(b, 37) * mul + a;
+    uint64 d = (Rotate(a, 25) + b) * mul;
+    return HashLen16(c, d, mul);
+  }
+  if (len >= 4) {
+    uint64 mul = k2 + len * 2;
+    uint64 a = Fetch32(s);
+    return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
+  }
+  if (len > 0) {
+    uint8 a = s[0];
+    uint8 b = s[len >> 1];
+    uint8 c = s[len - 1];
+    uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);
+    uint32 z = len + (static_cast<uint32>(c) << 2);
+    return ShiftMix(y * k2 ^ z * k0) * k2;
+  }
+  return k2;
+}
+
+// This probably works well for 16-byte strings as well, but it may be overkill
+// in that case.
+static uint64 HashLen17to32(const char *s, size_t len) {
+  uint64 mul = k2 + len * 2;
+  uint64 a = Fetch64(s) * k1;
+  uint64 b = Fetch64(s + 8);
+  uint64 c = Fetch64(s + len - 8) * mul;
+  uint64 d = Fetch64(s + len - 16) * k2;
+  return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d,
+                   a + Rotate(b + k2, 18) + c, mul);
+}
+
+// Return a 16-byte hash for 48 bytes.  Quick and dirty.
+// Callers do best to use "random-looking" values for a and b.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(
+    uint64 w, uint64 x, uint64 y, uint64 z, uint64 a, uint64 b) {
+  a += w;
+  b = Rotate(b + a + z, 21);
+  uint64 c = a;
+  a += x;
+  a += y;
+  b += Rotate(a, 44);
+  return make_pair(a + z, b + c);
+}
+
+// Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(
+    const char* s, uint64 a, uint64 b) {
+  return WeakHashLen32WithSeeds(Fetch64(s),
+                                Fetch64(s + 8),
+                                Fetch64(s + 16),
+                                Fetch64(s + 24),
+                                a,
+                                b);
+}
+
+// Return an 8-byte hash for 33 to 64 bytes.
+static uint64 HashLen33to64(const char *s, size_t len) {
+  uint64 mul = k2 + len * 2;
+  uint64 a = Fetch64(s) * k2;
+  uint64 b = Fetch64(s + 8);
+  uint64 c = Fetch64(s + len - 24);
+  uint64 d = Fetch64(s + len - 32);
+  uint64 e = Fetch64(s + 16) * k2;
+  uint64 f = Fetch64(s + 24) * 9;
+  uint64 g = Fetch64(s + len - 8);
+  uint64 h = Fetch64(s + len - 16) * mul;
+  uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
+  uint64 v = ((a + g) ^ d) + f + 1;
+  uint64 w = bswap_64((u + v) * mul) + h;
+  uint64 x = Rotate(e + f, 42) + c;
+  uint64 y = (bswap_64((v + w) * mul) + g) * mul;
+  uint64 z = e + f + c;
+  a = bswap_64((x + z) * mul + y) + b;
+  b = ShiftMix((z + a) * mul + d + h) * mul;
+  return b + x;
+}
+
+uint64 CityHash64(const char *s, size_t len) {
+  if (len <= 32) {
+    if (len <= 16) {
+      return HashLen0to16(s, len);
+    } else {
+      return HashLen17to32(s, len);
+    }
+  } else if (len <= 64) {
+    return HashLen33to64(s, len);
+  }
+
+  // For strings over 64 bytes we hash the end first, and then as we
+  // loop we keep 56 bytes of state: v, w, x, y, and z.
+  uint64 x = Fetch64(s + len - 40);
+  uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
+  uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
+  pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
+  pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+  x = x * k1 + Fetch64(s);
+
+  // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
+  len = (len - 1) & ~static_cast<size_t>(63);
+  do {
+    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+    x ^= w.second;
+    y += v.first + Fetch64(s + 40);
+    z = Rotate(z + w.first, 33) * k1;
+    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+    std::swap(z, x);
+    s += 64;
+    len -= 64;
+  } while (len != 0);
+  return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z,
+                   HashLen16(v.second, w.second) + x);
+}
+
+uint64 CityHash64WithSeed(const char *s, size_t len, uint64 seed) {
+  return CityHash64WithSeeds(s, len, k2, seed);
+}
+
+uint64 CityHash64WithSeeds(const char *s, size_t len,
+                           uint64 seed0, uint64 seed1) {
+  return HashLen16(CityHash64(s, len) - seed0, seed1);
+}
+
+// A subroutine for CityHash128().  Returns a decent 128-bit hash for strings
+// of any length representable in signed long.  Based on City and Murmur.
+static uint128 CityMurmur(const char *s, size_t len, uint128 seed) {
+  uint64 a = Uint128Low64(seed);
+  uint64 b = Uint128High64(seed);
+  uint64 c = 0;
+  uint64 d = 0;
+  signed long l = len - 16;
+  if (l <= 0) {  // len <= 16
+    a = ShiftMix(a * k1) * k1;
+    c = b * k1 + HashLen0to16(s, len);
+    d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));
+  } else {  // len > 16
+    c = HashLen16(Fetch64(s + len - 8) + k1, a);
+    d = HashLen16(b + len, c + Fetch64(s + len - 16));
+    a += d;
+    do {
+      a ^= ShiftMix(Fetch64(s) * k1) * k1;
+      a *= k1;
+      b ^= a;
+      c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;
+      c *= k1;
+      d ^= c;
+      s += 16;
+      l -= 16;
+    } while (l > 0);
+  }
+  a = HashLen16(a, c);
+  b = HashLen16(d, b);
+  return uint128(a ^ b, HashLen16(b, a));
+}
+
+uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
+  if (len < 128) {
+    return CityMurmur(s, len, seed);
+  }
+
+  // We expect len >= 128 to be the common case.  Keep 56 bytes of state:
+  // v, w, x, y, and z.
+  pair<uint64, uint64> v, w;
+  uint64 x = Uint128Low64(seed);
+  uint64 y = Uint128High64(seed);
+  uint64 z = len * k1;
+  v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
+  v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
+  w.first = Rotate(y + z, 35) * k1 + x;
+  w.second = Rotate(x + Fetch64(s + 88), 53) * k1;
+
+  // This is the same inner loop as CityHash64(), manually unrolled.
+  do {
+    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+    x ^= w.second;
+    y += v.first + Fetch64(s + 40);
+    z = Rotate(z + w.first, 33) * k1;
+    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+    std::swap(z, x);
+    s += 64;
+    x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+    y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+    x ^= w.second;
+    y += v.first + Fetch64(s + 40);
+    z = Rotate(z + w.first, 33) * k1;
+    v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+    w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+    std::swap(z, x);
+    s += 64;
+    len -= 128;
+  } while (LIKELY(len >= 128));
+  x += Rotate(v.first + z, 49) * k0;
+  y = y * k0 + Rotate(w.second, 37);
+  z = z * k0 + Rotate(w.first, 27);
+  w.first *= 9;
+  v.first *= k0;
+  // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
+  for (size_t tail_done = 0; tail_done < len; ) {
+    tail_done += 32;
+    y = Rotate(x + y, 42) * k0 + v.second;
+    w.first += Fetch64(s + len - tail_done + 16);
+    x = x * k0 + w.first;
+    z += w.second + Fetch64(s + len - tail_done);
+    w.second += v.first;
+    v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
+    v.first *= k0;
+  }
+  // At this point our 56 bytes of state should contain more than
+  // enough information for a strong 128-bit hash.  We use two
+  // different 56-byte-to-8-byte hashes to get a 16-byte final result.
+  x = HashLen16(x, v.first);
+  y = HashLen16(y + z, w.first);
+  return uint128(HashLen16(x + v.second, w.second) + y,
+                 HashLen16(x + w.second, y + v.second));
+}
+
+uint128 CityHash128(const char *s, size_t len) {
+  return len >= 16 ?
+      CityHash128WithSeed(s + 16, len - 16,
+                          uint128(Fetch64(s), Fetch64(s + 8) + k0)) :
+      CityHash128WithSeed(s, len, uint128(k0, k1));
+}
+
+// NFD NOTE
+// The following code block is commented out due to the following reasons.
+// - It requires the "citycrc.h" header file, which is not included in the
+//   NFD code base.
+// - The functions defined below are not used by the current NFD
+//   implementation.
+// The header file "citycrc.h" is available at
+// https://code.google.com/p/cityhash/source/browse/trunk/src/citycrc.h
+
+/*
+#ifdef __SSE4_2__
+#include <citycrc.h>
+#include <nmmintrin.h>
+
+// Requires len >= 240.
+static void CityHashCrc256Long(const char *s, size_t len,
+                               uint32 seed, uint64 *result) {
+  uint64 a = Fetch64(s + 56) + k0;
+  uint64 b = Fetch64(s + 96) + k0;
+  uint64 c = result[0] = HashLen16(b, len);
+  uint64 d = result[1] = Fetch64(s + 120) * k0 + len;
+  uint64 e = Fetch64(s + 184) + seed;
+  uint64 f = 0;
+  uint64 g = 0;
+  uint64 h = c + d;
+  uint64 x = seed;
+  uint64 y = 0;
+  uint64 z = 0;
+
+  // 240 bytes of input per iter.
+  size_t iters = len / 240;
+  len -= iters * 240;
+  do {
+#undef CHUNK
+#define CHUNK(r)                                \
+    PERMUTE3(x, z, y);                          \
+    b += Fetch64(s);                            \
+    c += Fetch64(s + 8);                        \
+    d += Fetch64(s + 16);                       \
+    e += Fetch64(s + 24);                       \
+    f += Fetch64(s + 32);                       \
+    a += b;                                     \
+    h += f;                                     \
+    b += c;                                     \
+    f += d;                                     \
+    g += e;                                     \
+    e += z;                                     \
+    g += x;                                     \
+    z = _mm_crc32_u64(z, b + g);                \
+    y = _mm_crc32_u64(y, e + h);                \
+    x = _mm_crc32_u64(x, f + a);                \
+    e = Rotate(e, r);                           \
+    c += e;                                     \
+    s += 40
+
+    CHUNK(0); PERMUTE3(a, h, c);
+    CHUNK(33); PERMUTE3(a, h, f);
+    CHUNK(0); PERMUTE3(b, h, f);
+    CHUNK(42); PERMUTE3(b, h, d);
+    CHUNK(0); PERMUTE3(b, h, e);
+    CHUNK(33); PERMUTE3(a, h, e);
+  } while (--iters > 0);
+
+  while (len >= 40) {
+    CHUNK(29);
+    e ^= Rotate(a, 20);
+    h += Rotate(b, 30);
+    g ^= Rotate(c, 40);
+    f += Rotate(d, 34);
+    PERMUTE3(c, h, g);
+    len -= 40;
+  }
+  if (len > 0) {
+    s = s + len - 40;
+    CHUNK(33);
+    e ^= Rotate(a, 43);
+    h += Rotate(b, 42);
+    g ^= Rotate(c, 41);
+    f += Rotate(d, 40);
+  }
+  result[0] ^= h;
+  result[1] ^= g;
+  g += h;
+  a = HashLen16(a, g + z);
+  x += y << 32;
+  b += x;
+  c = HashLen16(c, z) + h;
+  d = HashLen16(d, e + result[0]);
+  g += e;
+  h += HashLen16(x, f);
+  e = HashLen16(a, d) + g;
+  z = HashLen16(b, c) + a;
+  y = HashLen16(g, h) + c;
+  result[0] = e + z + y + x;
+  a = ShiftMix((a + y) * k0) * k0 + b;
+  result[1] += a + result[0];
+  a = ShiftMix(a * k0) * k0 + c;
+  result[2] = a + result[1];
+  a = ShiftMix((a + e) * k0) * k0;
+  result[3] = a + result[2];
+}
+
+// Requires len < 240.
+static void CityHashCrc256Short(const char *s, size_t len, uint64 *result) {
+  char buf[240];
+  memcpy(buf, s, len);
+  memset(buf + len, 0, 240 - len);
+  CityHashCrc256Long(buf, 240, ~static_cast<uint32>(len), result);
+}
+
+void CityHashCrc256(const char *s, size_t len, uint64 *result) {
+  if (LIKELY(len >= 240)) {
+    CityHashCrc256Long(s, len, 0, result);
+  } else {
+    CityHashCrc256Short(s, len, result);
+  }
+}
+
+uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) {
+  if (len <= 900) {
+    return CityHash128WithSeed(s, len, seed);
+  } else {
+    uint64 result[4];
+    CityHashCrc256(s, len, result);
+    uint64 u = Uint128High64(seed) + result[0];
+    uint64 v = Uint128Low64(seed) + result[1];
+    return uint128(HashLen16(u, v + result[2]),
+                   HashLen16(Rotate(v, 32), u * k0 + result[3]));
+  }
+}
+
+uint128 CityHashCrc128(const char *s, size_t len) {
+  if (len <= 900) {
+    return CityHash128(s, len);
+  } else {
+    uint64 result[4];
+    CityHashCrc256(s, len, result);
+    return uint128(result[2], result[3]);
+  }
+}
+
+#endif
+*/
diff --git a/daemon/common/city-hash.hpp b/daemon/common/city-hash.hpp
new file mode 100644
index 0000000..54a90cb
--- /dev/null
+++ b/daemon/common/city-hash.hpp
@@ -0,0 +1,112 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// http://code.google.com/p/cityhash/
+//
+// This file provides a few functions for hashing strings.  All of them are
+// high-quality functions in the sense that they pass standard tests such
+// as Austin Appleby's SMHasher.  They are also fast.
+//
+// For 64-bit x86 code, on short strings, we don't know of anything faster than
+// CityHash64 that is of comparable quality.  We believe our nearest competitor
+// is Murmur3.  For 64-bit x86 code, CityHash64 is an excellent choice for hash
+// tables and most other hashing (excluding cryptography).
+//
+// For 64-bit x86 code, on long strings, the picture is more complicated.
+// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
+// CityHashCrc128 appears to be faster than all competitors of comparable
+// quality.  CityHash128 is also good but not quite as fast.  We believe our
+// nearest competitor is Bob Jenkins' Spooky.  We don't have great data for
+// other 64-bit CPUs, but for long strings we know that Spooky is slightly
+// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
+// Note that CityHashCrc128 is declared in citycrc.h.
+//
+// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
+// is of comparable quality.  We believe our nearest competitor is Murmur3A.
+// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
+//
+// Functions in the CityHash family are not suitable for cryptography.
+//
+// Please see CityHash's README file for more details on our performance
+// measurements and so on.
+//
+// WARNING: This code has been only lightly tested on big-endian platforms!
+// It is known to work well on little-endian platforms that have a small penalty
+// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
+// It should work on all 32-bit and 64-bit platforms that allow unaligned reads;
+// bug reports are welcome.
+//
+// By the way, for some hash functions, given strings a and b, the hash
+// of a+b is easily derived from the hashes of a and b.  This property
+// doesn't hold for any hash functions in this file.
+
+#ifndef CITY_HASH_HPP
+#define CITY_HASH_HPP
+
+#include <stdlib.h>  // for size_t.
+#include <stdint.h>
+#include <utility>
+
+typedef uint8_t uint8;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+typedef std::pair<uint64, uint64> uint128;
+
+inline uint64 Uint128Low64(const uint128& x) { return x.first; }
+inline uint64 Uint128High64(const uint128& x) { return x.second; }
+
+// Hash function for a byte array.
+uint64 CityHash64(const char *buf, size_t len);
+
+// Hash function for a byte array.  For convenience, a 64-bit seed is also
+// hashed into the result.
+uint64 CityHash64WithSeed(const char *buf, size_t len, uint64 seed);
+
+// Hash function for a byte array.  For convenience, two seeds are also
+// hashed into the result.
+uint64 CityHash64WithSeeds(const char *buf, size_t len,
+                           uint64 seed0, uint64 seed1);
+
+// Hash function for a byte array.
+uint128 CityHash128(const char *s, size_t len);
+
+// Hash function for a byte array.  For convenience, a 128-bit seed is also
+// hashed into the result.
+uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed);
+
+// Hash function for a byte array.  Most useful in 32-bit binaries.
+uint32 CityHash32(const char *buf, size_t len);
+
+// Hash 128 input bits down to 64 bits of output.
+// This is intended to be a reasonably good hash function.
+inline uint64 Hash128to64(const uint128& x) {
+  // Murmur-inspired hashing.
+  const uint64 kMul = 0x9ddfea08eb382d69ULL;
+  uint64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
+  a ^= (a >> 47);
+  uint64 b = (Uint128High64(x) ^ a) * kMul;
+  b ^= (b >> 47);
+  b *= kMul;
+  return b;
+}
+
+#endif  // CITY_HASH_H_
diff --git a/daemon/common/config-file.cpp b/daemon/common/config-file.cpp
new file mode 100644
index 0000000..8d70349
--- /dev/null
+++ b/daemon/common/config-file.cpp
@@ -0,0 +1,138 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/config-file.hpp"
+
+#include <boost/property_tree/info_parser.hpp>
+
+#include <fstream>
+#include <sstream>
+
+namespace nfd {
+
+ConfigFile::ConfigFile(UnknownConfigSectionHandler unknownSectionCallback)
+  : m_unknownSectionCallback(unknownSectionCallback)
+{
+}
+
+void
+ConfigFile::throwErrorOnUnknownSection(const std::string& filename,
+                                       const std::string& sectionName,
+                                       const ConfigSection& section,
+                                       bool isDryRun)
+{
+  NDN_THROW(Error("Error processing configuration file " + filename +
+                  ": no module subscribed for section '" + sectionName + "'"));
+}
+
+void
+ConfigFile::ignoreUnknownSection(const std::string& filename,
+                                 const std::string& sectionName,
+                                 const ConfigSection& section,
+                                 bool isDryRun)
+{
+  // do nothing
+}
+
+bool
+ConfigFile::parseYesNo(const ConfigSection& node, const std::string& key,
+                       const std::string& sectionName)
+{
+  auto value = node.get_value<std::string>();
+
+  if (value == "yes") {
+    return true;
+  }
+  else if (value == "no") {
+    return false;
+  }
+
+  NDN_THROW(Error("Invalid value '" + value + "' for option '" +
+                  key + "' in section '" + sectionName + "'"));
+}
+
+void
+ConfigFile::addSectionHandler(const std::string& sectionName,
+                              ConfigSectionHandler subscriber)
+{
+  m_subscriptions[sectionName] = subscriber;
+}
+
+void
+ConfigFile::parse(const std::string& filename, bool isDryRun)
+{
+  std::ifstream inputFile(filename);
+  if (!inputFile.good() || !inputFile.is_open()) {
+    NDN_THROW(Error("Failed to read configuration file " + filename));
+  }
+  parse(inputFile, isDryRun, filename);
+  inputFile.close();
+}
+
+void
+ConfigFile::parse(const std::string& input, bool isDryRun, const std::string& filename)
+{
+  std::istringstream inputStream(input);
+  parse(inputStream, isDryRun, filename);
+}
+
+void
+ConfigFile::parse(std::istream& input, bool isDryRun, const std::string& filename)
+{
+  try {
+    boost::property_tree::read_info(input, m_global);
+  }
+  catch (const boost::property_tree::info_parser_error& error) {
+    NDN_THROW(Error("Failed to parse configuration file " + filename +
+                    ": " + error.message() + " on line " + to_string(error.line())));
+  }
+
+  process(isDryRun, filename);
+}
+
+void
+ConfigFile::parse(const ConfigSection& config, bool isDryRun, const std::string& filename)
+{
+  m_global = config;
+  process(isDryRun, filename);
+}
+
+void
+ConfigFile::process(bool isDryRun, const std::string& filename) const
+{
+  BOOST_ASSERT(!filename.empty());
+
+  for (const auto& i : m_global) {
+    try {
+      const ConfigSectionHandler& subscriber = m_subscriptions.at(i.first);
+      subscriber(i.second, isDryRun, filename);
+    }
+    catch (const std::out_of_range&) {
+      m_unknownSectionCallback(filename, i.first, i.second, isDryRun);
+    }
+  }
+}
+
+} // namespace nfd
diff --git a/daemon/common/config-file.hpp b/daemon/common/config-file.hpp
new file mode 100644
index 0000000..20e778b
--- /dev/null
+++ b/daemon/common/config-file.hpp
@@ -0,0 +1,180 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_COMMON_CONFIG_FILE_HPP
+#define NFD_DAEMON_COMMON_CONFIG_FILE_HPP
+
+#include "core/common.hpp"
+
+#include <boost/property_tree/ptree.hpp>
+
+namespace nfd {
+
+/** \brief a config file section
+ */
+using ConfigSection = boost::property_tree::ptree;
+
+/** \brief an optional config file section
+ */
+using OptionalConfigSection = boost::optional<const ConfigSection&>;
+
+/** \brief callback to process a config file section
+ */
+using ConfigSectionHandler = std::function<void(const ConfigSection& section, bool isDryRun,
+                                                const std::string& filename)>;
+
+/** \brief callback to process a config file section without a \p ConfigSectionHandler
+ */
+using UnknownConfigSectionHandler = std::function<void(const std::string& filename,
+                                                       const std::string& sectionName,
+                                                       const ConfigSection& section,
+                                                       bool isDryRun)>;
+
+/** \brief configuration file parsing utility
+ */
+class ConfigFile : noncopyable
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    using std::runtime_error::runtime_error;
+  };
+
+  explicit
+  ConfigFile(UnknownConfigSectionHandler unknownSectionCallback = throwErrorOnUnknownSection);
+
+public: // unknown section handlers
+  static void
+  throwErrorOnUnknownSection(const std::string& filename,
+                             const std::string& sectionName,
+                             const ConfigSection& section,
+                             bool isDryRun);
+
+  static void
+  ignoreUnknownSection(const std::string& filename,
+                       const std::string& sectionName,
+                       const ConfigSection& section,
+                       bool isDryRun);
+
+public: // parse helpers
+  /** \brief parse a config option that can be either "yes" or "no"
+   *  \retval true "yes"
+   *  \retval false "no"
+   *  \throw Error the value is neither "yes" nor "no"
+   */
+  static bool
+  parseYesNo(const ConfigSection& node, const std::string& key, const std::string& sectionName);
+
+  static bool
+  parseYesNo(const ConfigSection::value_type& option, const std::string& sectionName)
+  {
+    return parseYesNo(option.second, option.first, sectionName);
+  }
+
+  /**
+   * \brief parse a numeric (integral or floating point) config option
+   * \tparam T an arithmetic type
+   *
+   * \return the numeric value of the parsed option
+   * \throw Error the value cannot be converted to the specified type
+   */
+  template<typename T>
+  static T
+  parseNumber(const ConfigSection& node, const std::string& key, const std::string& sectionName)
+  {
+    static_assert(std::is_arithmetic<T>::value, "T must be an arithmetic type");
+
+    boost::optional<T> value = node.get_value_optional<T>();
+    if (value) {
+      return *value;
+    }
+    NDN_THROW(Error("Invalid value '" + node.get_value<std::string>() +
+                    "' for option '" + key + "' in section '" + sectionName + "'"));
+  }
+
+  template <typename T>
+  static T
+  parseNumber(const ConfigSection::value_type& option, const std::string& sectionName)
+  {
+    return parseNumber<T>(option.second, option.first, sectionName);
+  }
+
+public: // setup and parsing
+  /// \brief setup notification of configuration file sections
+  void
+  addSectionHandler(const std::string& sectionName,
+                    ConfigSectionHandler subscriber);
+
+  /**
+   * \param filename file to parse
+   * \param isDryRun true if performing a dry run of configuration, false otherwise
+   * \throws ConfigFile::Error if file not found
+   * \throws ConfigFile::Error if parse error
+   */
+  void
+  parse(const std::string& filename, bool isDryRun);
+
+  /**
+   * \param input configuration (as a string) to parse
+   * \param isDryRun true if performing a dry run of configuration, false otherwise
+   * \param filename logical filename of the config file, can appear in error messages
+   * \throws ConfigFile::Error if file not found
+   * \throws ConfigFile::Error if parse error
+   */
+  void
+  parse(const std::string& input, bool isDryRun, const std::string& filename);
+
+  /**
+   * \param input stream to parse
+   * \param isDryRun true if performing a dry run of configuration, false otherwise
+   * \param filename logical filename of the config file, can appear in error messages
+   * \throws ConfigFile::Error if parse error
+   */
+  void
+  parse(std::istream& input, bool isDryRun, const std::string& filename);
+
+  /**
+   * \param config ConfigSection that needs to be processed
+   * \param isDryRun true if performing a dry run of configuration, false otherwise
+   * \param filename logical filename of the config file, can appear in error messages
+   * \throws ConfigFile::Error if parse error
+   */
+  void
+  parse(const ConfigSection& config, bool isDryRun, const std::string& filename);
+
+private:
+  void
+  process(bool isDryRun, const std::string& filename) const;
+
+private:
+  UnknownConfigSectionHandler m_unknownSectionCallback;
+  std::map<std::string, ConfigSectionHandler> m_subscriptions;
+  ConfigSection m_global;
+};
+
+} // namespace nfd
+
+#endif // NFD_DAEMON_COMMON_CONFIG_FILE_HPP
diff --git a/daemon/common/counter.hpp b/daemon/common/counter.hpp
new file mode 100644
index 0000000..4619b35
--- /dev/null
+++ b/daemon/common/counter.hpp
@@ -0,0 +1,134 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_COMMON_COUNTER_HPP
+#define NFD_DAEMON_COMMON_COUNTER_HPP
+
+#include "core/common.hpp"
+
+namespace nfd {
+
+/** \brief represents a counter that encloses an integer value
+ *
+ *  SimpleCounter is noncopyable, because increment should be called on the counter,
+ *  not a copy of it; it's implicitly convertible to an integral type to be observed
+ */
+class SimpleCounter : noncopyable
+{
+public:
+  typedef uint64_t rep;
+
+  /** \brief observe the counter
+   */
+  operator rep() const noexcept
+  {
+    return m_value;
+  }
+
+  /** \brief replace the counter value
+   */
+  void
+  set(rep value) noexcept
+  {
+    m_value = value;
+  }
+
+protected:
+  rep m_value = 0;
+};
+
+/** \brief represents a counter of number of packets
+ *
+ *  \warning The counter value may wrap after exceeding the range of underlying integer type.
+ */
+class PacketCounter : public SimpleCounter
+{
+public:
+  /** \brief increment the counter by one
+   */
+  PacketCounter&
+  operator++() noexcept
+  {
+    ++m_value;
+    return *this;
+  }
+  // postfix ++ operator is not provided because it's not needed
+};
+
+/** \brief represents a counter of number of bytes
+ *
+ *  \warning The counter value may wrap after exceeding the range of underlying integer type.
+ */
+class ByteCounter : public SimpleCounter
+{
+public:
+  /** \brief increase the counter
+   */
+  ByteCounter&
+  operator+=(rep n) noexcept
+  {
+    m_value += n;
+    return *this;
+  }
+};
+
+/** \brief provides a counter that observes the size of a table
+ *  \tparam T a type that provides a size() const member function
+ *
+ *  if table not specified in constructor, it can be added later by invoking observe()
+ */
+template<typename T>
+class SizeCounter : noncopyable
+{
+public:
+  typedef size_t Rep;
+
+  explicit constexpr
+  SizeCounter(const T* table = nullptr) noexcept
+    : m_table(table)
+  {
+  }
+
+  void
+  observe(const T* table) noexcept
+  {
+    m_table = table;
+  }
+
+  /** \brief observe the counter
+   */
+  operator Rep() const
+  {
+    BOOST_ASSERT(m_table != nullptr);
+    return m_table->size();
+  }
+
+private:
+  const T* m_table;
+};
+
+} // namespace nfd
+
+#endif // NFD_DAEMON_COMMON_COUNTER_HPP
diff --git a/daemon/global.cpp b/daemon/common/global.cpp
similarity index 98%
rename from daemon/global.cpp
rename to daemon/common/global.cpp
index bd1dac2..a0fd88f 100644
--- a/daemon/global.cpp
+++ b/daemon/common/global.cpp
@@ -23,7 +23,7 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 
diff --git a/daemon/global.hpp b/daemon/common/global.hpp
similarity index 94%
rename from daemon/global.hpp
rename to daemon/common/global.hpp
index 05bc577..1e1fce8 100644
--- a/daemon/global.hpp
+++ b/daemon/common/global.hpp
@@ -22,8 +22,8 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  **/
 
-#ifndef NFD_DAEMON_GLOBAL_HPP
-#define NFD_DAEMON_GLOBAL_HPP
+#ifndef NFD_DAEMON_COMMON_GLOBAL_HPP
+#define NFD_DAEMON_COMMON_GLOBAL_HPP
 
 #include "core/common.hpp"
 
@@ -72,4 +72,4 @@
 
 } // namespace nfd
 
-#endif // NFD_DAEMON_GLOBAL_HPP
+#endif // NFD_DAEMON_COMMON_GLOBAL_HPP
diff --git a/daemon/common/logger.hpp b/daemon/common/logger.hpp
new file mode 100644
index 0000000..9a2637d
--- /dev/null
+++ b/daemon/common/logger.hpp
@@ -0,0 +1,44 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_COMMON_LOGGER_HPP
+#define NFD_DAEMON_COMMON_LOGGER_HPP
+
+#include <ndn-cxx/util/logger.hpp>
+
+#define NFD_LOG_INIT(name)                         NDN_LOG_INIT(nfd.name)
+#define NFD_LOG_MEMBER_DECL()                      NDN_LOG_MEMBER_DECL()
+#define NFD_LOG_MEMBER_DECL_SPECIALIZED(cls)       NDN_LOG_MEMBER_DECL_SPECIALIZED(cls)
+#define NFD_LOG_MEMBER_INIT(cls, name)             NDN_LOG_MEMBER_INIT(cls, nfd.name)
+#define NFD_LOG_MEMBER_INIT_SPECIALIZED(cls, name) NDN_LOG_MEMBER_INIT_SPECIALIZED(cls, nfd.name)
+
+#define NFD_LOG_TRACE NDN_LOG_TRACE
+#define NFD_LOG_DEBUG NDN_LOG_DEBUG
+#define NFD_LOG_INFO  NDN_LOG_INFO
+#define NFD_LOG_WARN  NDN_LOG_WARN
+#define NFD_LOG_ERROR NDN_LOG_ERROR
+#define NFD_LOG_FATAL NDN_LOG_FATAL
+
+#endif // NFD_DAEMON_COMMON_LOGGER_HPP
diff --git a/daemon/common/privilege-helper.cpp b/daemon/common/privilege-helper.cpp
new file mode 100644
index 0000000..7cdfcd0
--- /dev/null
+++ b/daemon/common/privilege-helper.cpp
@@ -0,0 +1,163 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/privilege-helper.hpp"
+#include "common/logger.hpp"
+
+#include <pwd.h>
+#include <grp.h>
+
+namespace nfd {
+
+NFD_LOG_INIT(PrivilegeHelper);
+
+#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
+uid_t PrivilegeHelper::s_normalUid = ::geteuid();
+gid_t PrivilegeHelper::s_normalGid = ::getegid();
+
+uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
+gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
+#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
+
+void
+PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
+{
+#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
+  static const size_t MAX_GROUP_BUFFER_SIZE = 16384; // 16 KiB
+  static const size_t MAX_PASSWD_BUFFER_SIZE = 16384;
+
+  static const size_t FALLBACK_GROUP_BUFFER_SIZE = 1024;
+  static const size_t FALLBACK_PASSWD_BUFFER_SIZE = 1024;
+
+  NFD_LOG_TRACE("initializing with user \"" << userName << "\""
+                << " group \"" << groupName << "\"");
+
+  // workflow from man getpwnam_r
+
+  if (!groupName.empty()) {
+    static long groupSize = ::sysconf(_SC_GETGR_R_SIZE_MAX);
+
+    if (groupSize == -1)
+      groupSize = FALLBACK_GROUP_BUFFER_SIZE;
+
+    std::vector<char> groupBuffer(static_cast<size_t>(groupSize));
+    struct group group;
+    struct group* groupResult = nullptr;
+
+    int errorCode = getgrnam_r(groupName.data(), &group,
+                               groupBuffer.data(), groupBuffer.size(), &groupResult);
+
+    while (errorCode == ERANGE) {
+      if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
+        throw Error("Cannot allocate large enough buffer for struct group");
+
+      groupBuffer.resize(groupBuffer.size() * 2);
+      errorCode = getgrnam_r(groupName.data(), &group,
+                             groupBuffer.data(), groupBuffer.size(), &groupResult);
+    }
+
+    if (errorCode != 0 || !groupResult)
+      throw Error("Failed to get gid for \"" + groupName + "\"");
+
+    s_normalGid = group.gr_gid;
+  }
+
+  if (!userName.empty()) {
+    static long passwdSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
+
+    if (passwdSize == -1)
+      passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
+
+    std::vector<char> passwdBuffer(static_cast<size_t>(passwdSize));
+    struct passwd passwd;
+    struct passwd* passwdResult = nullptr;
+
+    int errorCode = getpwnam_r(userName.data(), &passwd,
+                               passwdBuffer.data(), passwdBuffer.size(), &passwdResult);
+
+    while (errorCode == ERANGE) {
+      if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
+        throw Error("Cannot allocate large enough buffer for struct passwd");
+
+      passwdBuffer.resize(passwdBuffer.size() * 2);
+      errorCode = getpwnam_r(userName.data(), &passwd,
+                             passwdBuffer.data(), passwdBuffer.size(), &passwdResult);
+    }
+
+    if (errorCode != 0 || !passwdResult)
+      throw Error("Failed to get uid for \"" + userName + "\"");
+
+    s_normalUid = passwd.pw_uid;
+  }
+#else
+  if (!userName.empty() || !groupName.empty()) {
+    throw Error("Dropping and raising privileges is not supported on this platform");
+  }
+#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
+}
+
+void
+PrivilegeHelper::drop()
+{
+#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
+  if (::geteuid() == s_normalUid && ::getegid() == s_normalGid)
+    return;
+
+  NFD_LOG_TRACE("dropping to effective gid=" << s_normalGid);
+  if (::setegid(s_normalGid) != 0)
+    throw Error("Failed to drop to effective gid=" + to_string(s_normalGid));
+
+  NFD_LOG_TRACE("dropping to effective uid=" << s_normalUid);
+  if (::seteuid(s_normalUid) != 0)
+    throw Error("Failed to drop to effective uid=" + to_string(s_normalUid));
+
+  NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
+#else
+  NFD_LOG_WARN("Dropping privileges is not supported on this platform");
+#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
+}
+
+void
+PrivilegeHelper::raise()
+{
+#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
+  if (::geteuid() == s_privilegedUid && ::getegid() == s_privilegedGid)
+    return;
+
+  NFD_LOG_TRACE("elevating to effective uid=" << s_privilegedUid);
+  if (::seteuid(s_privilegedUid) != 0)
+    throw Error("Failed to elevate to effective uid=" + to_string(s_privilegedUid));
+
+  NFD_LOG_TRACE("elevating to effective gid=" << s_privilegedGid);
+  if (::setegid(s_privilegedGid) != 0)
+    throw Error("Failed to elevate to effective gid=" + to_string(s_privilegedGid));
+
+  NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
+#else
+  NFD_LOG_WARN("Elevating privileges is not supported on this platform");
+#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
+}
+
+} // namespace nfd
diff --git a/daemon/common/privilege-helper.hpp b/daemon/common/privilege-helper.hpp
new file mode 100644
index 0000000..52daf84
--- /dev/null
+++ b/daemon/common/privilege-helper.hpp
@@ -0,0 +1,99 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_COMMON_PRIVILEGE_HELPER_HPP
+#define NFD_DAEMON_COMMON_PRIVILEGE_HELPER_HPP
+
+#include "core/common.hpp"
+
+#include <unistd.h>
+
+namespace nfd {
+
+class PrivilegeHelper
+{
+public:
+  /** \brief represents a serious seteuid/gid failure
+   *
+   *  This should only be caught by main as part of a graceful program termination.
+   *  \note This is not an std::exception and NDN_THROW should not be used.
+   */
+  class Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : m_whatMessage(what)
+    {
+    }
+
+    const char*
+    what() const
+    {
+      return m_whatMessage.data();
+    }
+
+  private:
+    const std::string m_whatMessage;
+  };
+
+  static void
+  initialize(const std::string& userName, const std::string& groupName);
+
+  static void
+  drop();
+
+  template<class F>
+  static void
+  runElevated(F&& f)
+  {
+    raise();
+    try {
+      f();
+    }
+    catch (...) {
+      drop();
+      throw;
+    }
+    drop();
+  }
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  static void
+  raise();
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
+  static uid_t s_normalUid;
+  static gid_t s_normalGid;
+
+  static uid_t s_privilegedUid;
+  static gid_t s_privilegedGid;
+#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
+};
+
+} // namespace nfd
+
+#endif // NFD_DAEMON_COMMON_PRIVILEGE_HELPER_HPP
diff --git a/daemon/face/channel-log.hpp b/daemon/face/channel-log.hpp
index 59edf52..375c23a 100644
--- a/daemon/face/channel-log.hpp
+++ b/daemon/face/channel-log.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -26,7 +26,7 @@
 #ifndef NFD_DAEMON_FACE_CHANNEL_LOG_HPP
 #define NFD_DAEMON_FACE_CHANNEL_LOG_HPP
 
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 /** \defgroup ChannelLogging Channel logging macros
  *
diff --git a/daemon/face/datagram-transport.hpp b/daemon/face/datagram-transport.hpp
index 135035f..fcde63b 100644
--- a/daemon/face/datagram-transport.hpp
+++ b/daemon/face/datagram-transport.hpp
@@ -28,7 +28,7 @@
 
 #include "transport.hpp"
 #include "socket-utils.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <array>
 
diff --git a/daemon/face/ethernet-channel.cpp b/daemon/face/ethernet-channel.cpp
index 4b5a072..9c27ada 100644
--- a/daemon/face/ethernet-channel.cpp
+++ b/daemon/face/ethernet-channel.cpp
@@ -27,7 +27,7 @@
 #include "ethernet-protocol.hpp"
 #include "generic-link-service.hpp"
 #include "unicast-ethernet-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <boost/range/adaptor/map.hpp>
 #include <pcap/pcap.h>
diff --git a/daemon/face/ethernet-transport.cpp b/daemon/face/ethernet-transport.cpp
index 0e69745..a2f3e9b 100644
--- a/daemon/face/ethernet-transport.cpp
+++ b/daemon/face/ethernet-transport.cpp
@@ -25,7 +25,7 @@
 
 #include "ethernet-transport.hpp"
 #include "ethernet-protocol.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <pcap/pcap.h>
 
diff --git a/daemon/face/face-log.hpp b/daemon/face/face-log.hpp
index 55022d1..b193d82 100644
--- a/daemon/face/face-log.hpp
+++ b/daemon/face/face-log.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -26,7 +26,7 @@
 #ifndef NFD_DAEMON_FACE_FACE_LOG_HPP
 #define NFD_DAEMON_FACE_FACE_LOG_HPP
 
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/face/face-system.cpp b/daemon/face/face-system.cpp
index 260eea7..67738aa 100644
--- a/daemon/face/face-system.cpp
+++ b/daemon/face/face-system.cpp
@@ -26,7 +26,7 @@
 #include "face-system.hpp"
 #include "protocol-factory.hpp"
 #include "netdev-bound.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 #include "fw/face-table.hpp"
 
 namespace nfd {
diff --git a/daemon/face/face-system.hpp b/daemon/face/face-system.hpp
index 833da1b..2bcdfad 100644
--- a/daemon/face/face-system.hpp
+++ b/daemon/face/face-system.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -27,8 +27,9 @@
 #define NFD_DAEMON_FACE_FACE_SYSTEM_HPP
 
 #include "channel.hpp"
-#include "core/config-file.hpp"
-#include "core/network-predicate.hpp"
+#include "network-predicate.hpp"
+#include "common/config-file.hpp"
+
 #include <ndn-cxx/net/network-address.hpp>
 #include <ndn-cxx/net/network-interface.hpp>
 #include <ndn-cxx/net/network-monitor.hpp>
diff --git a/daemon/face/internal-face.cpp b/daemon/face/internal-face.cpp
index f82bd58..764dfd7 100644
--- a/daemon/face/internal-face.cpp
+++ b/daemon/face/internal-face.cpp
@@ -26,7 +26,7 @@
 #include "internal-face.hpp"
 #include "generic-link-service.hpp"
 #include "internal-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/face/internal-transport.cpp b/daemon/face/internal-transport.cpp
index 5b3fcac..18bfe0a 100644
--- a/daemon/face/internal-transport.cpp
+++ b/daemon/face/internal-transport.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "internal-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/face/link-service.hpp b/daemon/face/link-service.hpp
index b8e8749..0caa857 100644
--- a/daemon/face/link-service.hpp
+++ b/daemon/face/link-service.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -26,9 +26,9 @@
 #ifndef NFD_DAEMON_FACE_LINK_SERVICE_HPP
 #define NFD_DAEMON_FACE_LINK_SERVICE_HPP
 
-#include "core/counter.hpp"
 #include "face-log.hpp"
 #include "transport.hpp"
+#include "common/counter.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/face/lp-reassembler.cpp b/daemon/face/lp-reassembler.cpp
index 918d296..d19f799 100644
--- a/daemon/face/lp-reassembler.cpp
+++ b/daemon/face/lp-reassembler.cpp
@@ -25,7 +25,7 @@
 
 #include "lp-reassembler.hpp"
 #include "link-service.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <numeric>
 
diff --git a/daemon/face/lp-reliability.cpp b/daemon/face/lp-reliability.cpp
index f65d3c3..7f7ee14 100644
--- a/daemon/face/lp-reliability.cpp
+++ b/daemon/face/lp-reliability.cpp
@@ -26,7 +26,7 @@
 #include "lp-reliability.hpp"
 #include "generic-link-service.hpp"
 #include "transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/face/multicast-ethernet-transport.cpp b/daemon/face/multicast-ethernet-transport.cpp
index 80f13ea..1295764 100644
--- a/daemon/face/multicast-ethernet-transport.cpp
+++ b/daemon/face/multicast-ethernet-transport.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "multicast-ethernet-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <cerrno>         // for errno
 #include <cstring>        // for memcpy(), strerror(), strncpy()
diff --git a/daemon/face/multicast-udp-transport.cpp b/daemon/face/multicast-udp-transport.cpp
index 2c61527..689b7e0 100644
--- a/daemon/face/multicast-udp-transport.cpp
+++ b/daemon/face/multicast-udp-transport.cpp
@@ -27,7 +27,7 @@
 #include "socket-utils.hpp"
 #include "udp-protocol.hpp"
 
-#include "core/privilege-helper.hpp"
+#include "common/privilege-helper.hpp"
 
 #include <boost/functional/hash.hpp>
 
diff --git a/daemon/face/netdev-bound.cpp b/daemon/face/netdev-bound.cpp
index 5ed975d..124ea3a 100644
--- a/daemon/face/netdev-bound.cpp
+++ b/daemon/face/netdev-bound.cpp
@@ -25,7 +25,7 @@
 
 #include "netdev-bound.hpp"
 #include "face-system.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/face/network-predicate.cpp b/daemon/face/network-predicate.cpp
new file mode 100644
index 0000000..31a2cf8
--- /dev/null
+++ b/daemon/face/network-predicate.cpp
@@ -0,0 +1,227 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "network-predicate.hpp"
+#include "common/config-file.hpp"
+#include "core/network.hpp"
+
+#include <fnmatch.h>
+
+namespace nfd {
+namespace face {
+
+NetworkPredicateBase::NetworkPredicateBase()
+{
+  this->clear();
+}
+
+NetworkPredicateBase::~NetworkPredicateBase() = default;
+
+void
+NetworkPredicateBase::clear()
+{
+  m_whitelist = std::set<std::string>{"*"};
+  m_blacklist.clear();
+}
+
+void
+NetworkPredicateBase::parseList(std::set<std::string>& set,
+                                const boost::property_tree::ptree& list,
+                                const std::string& section)
+{
+  set.clear();
+
+  for (const auto& item : list) {
+    if (item.first == "*") {
+      // insert wildcard
+      set.insert(item.first);
+    }
+    else {
+      if (!isRuleSupported(item.first)) {
+        NDN_THROW(ConfigFile::Error("Unrecognized rule '" + item.first +
+                                    "' in section '" + section + "'"));
+      }
+
+      auto value = item.second.get_value<std::string>();
+      if (!isRuleValid(item.first, value)) {
+        NDN_THROW(ConfigFile::Error("Malformed " + item.first + " '" + value +
+                                    "' in section '" + section + "'"));
+      }
+      set.insert(value);
+    }
+  }
+}
+
+void
+NetworkPredicateBase::parseList(std::set<std::string>& set,
+                                std::initializer_list<std::pair<std::string, std::string>> list)
+{
+  set.clear();
+
+  for (const auto& item : list) {
+    if (item.first == "*") {
+      // insert wildcard
+      set.insert(item.first);
+    }
+    else {
+      if (!isRuleSupported(item.first)) {
+        NDN_THROW(std::runtime_error("Unrecognized rule '" + item.first + "'"));
+      }
+
+      if (!isRuleValid(item.first, item.second)) {
+        NDN_THROW(std::runtime_error("Malformed " + item.first + " '" + item.second + "'"));
+      }
+      set.insert(item.second);
+    }
+  }
+}
+
+void
+NetworkPredicateBase::parseWhitelist(const boost::property_tree::ptree& list)
+{
+  parseList(m_whitelist, list, "whitelist");
+}
+
+void
+NetworkPredicateBase::parseBlacklist(const boost::property_tree::ptree& list)
+{
+  parseList(m_blacklist, list, "blacklist");
+}
+
+void
+NetworkPredicateBase::assign(std::initializer_list<std::pair<std::string, std::string>> whitelist,
+                             std::initializer_list<std::pair<std::string, std::string>> blacklist)
+{
+  parseList(m_whitelist, whitelist);
+  parseList(m_blacklist, blacklist);
+}
+
+bool
+NetworkInterfacePredicate::isRuleSupported(const std::string& key)
+{
+  return key == "ifname" || key == "ether" || key == "subnet";
+}
+
+bool
+NetworkInterfacePredicate::isRuleValid(const std::string& key, const std::string& value)
+{
+  if (key == "ifname") {
+    // very basic sanity check for interface names
+    return !value.empty();
+  }
+  else if (key == "ether") {
+    // validate ethernet address
+    return !ndn::ethernet::Address::fromString(value).isNull();
+  }
+  else if (key == "subnet") {
+    // example subnet: 10.0.0.0/8
+    return Network::isValidCidr(value);
+  }
+  else {
+    NDN_THROW(std::logic_error("Only supported rules are expected"));
+  }
+}
+
+bool
+IpAddressPredicate::isRuleSupported(const std::string& key)
+{
+  return key == "subnet";
+}
+
+bool
+IpAddressPredicate::isRuleValid(const std::string& key, const std::string& value)
+{
+  if (key == "subnet") {
+    // example subnet: 10.0.0.0/8
+    return Network::isValidCidr(value);
+  }
+  else {
+    NDN_THROW(std::logic_error("Only supported rules are expected"));
+  }
+}
+
+bool
+NetworkPredicateBase::operator==(const NetworkPredicateBase& other) const
+{
+  return this->m_whitelist == other.m_whitelist &&
+         this->m_blacklist == other.m_blacklist;
+}
+
+static bool
+doesMatchPattern(const std::string& ifname, const std::string& pattern)
+{
+  // use fnmatch(3) to provide unix glob-style matching for interface names
+  // fnmatch returns 0 if there is a match
+  return ::fnmatch(pattern.data(), ifname.data(), 0) == 0;
+}
+
+static bool
+doesNetifMatchRule(const ndn::net::NetworkInterface& netif, const std::string& rule)
+{
+  // if '/' is in rule, this is a subnet, check if IP in subnet
+  if (rule.find('/') != std::string::npos) {
+    Network n = boost::lexical_cast<Network>(rule);
+    for (const auto& addr : netif.getNetworkAddresses()) {
+      if (n.doesContain(addr.getIp())) {
+        return true;
+      }
+    }
+  }
+
+  return rule == "*" ||
+         doesMatchPattern(netif.getName(), rule) ||
+         netif.getEthernetAddress().toString() == rule;
+}
+
+bool
+NetworkInterfacePredicate::operator()(const ndn::net::NetworkInterface& netif) const
+{
+  return std::any_of(m_whitelist.begin(), m_whitelist.end(), bind(&doesNetifMatchRule, std::cref(netif), _1)) &&
+         std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesNetifMatchRule, std::cref(netif), _1));
+}
+
+static bool
+doesAddressMatchRule(const boost::asio::ip::address& address, const std::string& rule)
+{
+  // if '/' is in rule, this is a subnet, check if IP in subnet
+  if (rule.find('/') != std::string::npos) {
+    Network n = boost::lexical_cast<Network>(rule);
+    if (n.doesContain(address)) {
+      return true;
+    }
+  }
+
+  return rule == "*";
+}
+
+bool
+IpAddressPredicate::operator()(const boost::asio::ip::address& address) const
+{
+  return std::any_of(m_whitelist.begin(), m_whitelist.end(), bind(&doesAddressMatchRule, std::cref(address), _1)) &&
+         std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesAddressMatchRule, std::cref(address), _1));
+}
+
+} // namespace face
+} // namespace nfd
diff --git a/daemon/face/network-predicate.hpp b/daemon/face/network-predicate.hpp
new file mode 100644
index 0000000..27ac8b1
--- /dev/null
+++ b/daemon/face/network-predicate.hpp
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_FACE_NETWORK_PREDICATE_HPP
+#define NFD_DAEMON_FACE_NETWORK_PREDICATE_HPP
+
+#include "core/common.hpp"
+
+#include <ndn-cxx/net/network-interface.hpp>
+
+namespace nfd {
+namespace face {
+
+class NetworkPredicateBase
+{
+public:
+  NetworkPredicateBase();
+
+  virtual
+  ~NetworkPredicateBase();
+
+  /**
+   * \brief Set the whitelist to "*" and clear the blacklist
+   */
+  void
+  clear();
+
+  void
+  parseWhitelist(const boost::property_tree::ptree& list);
+
+  void
+  parseBlacklist(const boost::property_tree::ptree& list);
+
+  void
+  assign(std::initializer_list<std::pair<std::string, std::string>> whitelist,
+         std::initializer_list<std::pair<std::string, std::string>> blacklist);
+
+  bool
+  operator==(const NetworkPredicateBase& other) const;
+
+  bool
+  operator!=(const NetworkPredicateBase& other) const
+  {
+    return !this->operator==(other);
+  }
+
+private:
+  virtual bool
+  isRuleSupported(const std::string& key) = 0;
+
+  virtual bool
+  isRuleValid(const std::string& key, const std::string& value) = 0;
+
+  void
+  parseList(std::set<std::string>& set, const boost::property_tree::ptree& list, const std::string& section);
+
+  void
+  parseList(std::set<std::string>& set, std::initializer_list<std::pair<std::string, std::string>> list);
+
+PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+  std::set<std::string> m_whitelist;
+  std::set<std::string> m_blacklist;
+};
+
+/**
+ * \brief Represents a predicate to accept or reject a ndn::net::NetworkInterface.
+ *
+ * The predicate consists of a whitelist and a blacklist. Whitelist and blacklist can contain,
+ * in no particular order, interface names (e.g., `ifname eth0`), MAC addresses (e.g., `ether
+ * 85:3b:4d:d3:5f:c2`), IPv4 and IPv6 subnets (e.g., `subnet 192.0.2.0/24` or `subnet
+ * 2001:db8:2::/64`), or a wildcard (`*`) that matches all interfaces. A
+ * ndn::net::NetworkInterface is accepted if it matches any entry in the whitelist and none of
+ * the entries in the blacklist.
+ */
+class NetworkInterfacePredicate : public NetworkPredicateBase
+{
+public:
+  bool
+  operator()(const ndn::net::NetworkInterface& netif) const;
+
+private:
+  bool
+  isRuleSupported(const std::string& key) final;
+
+  bool
+  isRuleValid(const std::string& key, const std::string& value) final;
+};
+
+/**
+ * \brief Represents a predicate to accept or reject an IP address.
+ *
+ * The predicate consists of a whitelist and a blacklist. Whitelist and blacklist can contain,
+ * in no particular order, IPv4 and IPv6 subnets (e.g., `subnet 192.0.2.0/24` or `subnet
+ * 2001:db8:2::/64`) or a wildcard (`*`) that matches all IP addresses. An IP address is
+ * accepted if it matches any entry in the whitelist and none of the entries in the blacklist.
+ */
+class IpAddressPredicate : public NetworkPredicateBase
+{
+public:
+  bool
+  operator()(const boost::asio::ip::address& address) const;
+
+private:
+  bool
+  isRuleSupported(const std::string& key) final;
+
+  bool
+  isRuleValid(const std::string& key, const std::string& value) final;
+};
+
+} // namespace face
+} // namespace nfd
+
+#endif // NFD_DAEMON_FACE_NETWORK_PREDICATE_HPP
diff --git a/daemon/face/stream-transport.hpp b/daemon/face/stream-transport.hpp
index eb7de92..e0a7d6d 100644
--- a/daemon/face/stream-transport.hpp
+++ b/daemon/face/stream-transport.hpp
@@ -28,7 +28,7 @@
 
 #include "transport.hpp"
 #include "socket-utils.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <queue>
 
diff --git a/daemon/face/tcp-channel.cpp b/daemon/face/tcp-channel.cpp
index 7ffb0f3..dc0576f 100644
--- a/daemon/face/tcp-channel.cpp
+++ b/daemon/face/tcp-channel.cpp
@@ -26,7 +26,7 @@
 #include "tcp-channel.hpp"
 #include "generic-link-service.hpp"
 #include "tcp-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/face/tcp-transport.cpp b/daemon/face/tcp-transport.cpp
index 90c1825..58c4add 100644
--- a/daemon/face/tcp-transport.cpp
+++ b/daemon/face/tcp-transport.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "tcp-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #if defined(__linux__)
 #include <linux/sockios.h>
diff --git a/daemon/face/transport.hpp b/daemon/face/transport.hpp
index 8bbfe86..aaea75a 100644
--- a/daemon/face/transport.hpp
+++ b/daemon/face/transport.hpp
@@ -26,8 +26,8 @@
 #ifndef NFD_DAEMON_FACE_TRANSPORT_HPP
 #define NFD_DAEMON_FACE_TRANSPORT_HPP
 
-#include "core/counter.hpp"
 #include "face-log.hpp"
+#include "common/counter.hpp"
 
 #include <ndn-cxx/encoding/nfd-constants.hpp>
 
diff --git a/daemon/face/udp-channel.cpp b/daemon/face/udp-channel.cpp
index b9da25e..7f4a4d9 100644
--- a/daemon/face/udp-channel.cpp
+++ b/daemon/face/udp-channel.cpp
@@ -26,7 +26,7 @@
 #include "udp-channel.hpp"
 #include "generic-link-service.hpp"
 #include "unicast-udp-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/face/udp-factory.cpp b/daemon/face/udp-factory.cpp
index 2c8cf20..54b00b1 100644
--- a/daemon/face/udp-factory.cpp
+++ b/daemon/face/udp-factory.cpp
@@ -26,7 +26,7 @@
 #include "udp-factory.hpp"
 #include "generic-link-service.hpp"
 #include "multicast-udp-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <boost/range/adaptor/map.hpp>
 #include <boost/range/algorithm/copy.hpp>
diff --git a/daemon/face/unicast-ethernet-transport.cpp b/daemon/face/unicast-ethernet-transport.cpp
index 3ed7800..97e5c4e 100644
--- a/daemon/face/unicast-ethernet-transport.cpp
+++ b/daemon/face/unicast-ethernet-transport.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "unicast-ethernet-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <stdio.h>  // for snprintf()
 
diff --git a/daemon/face/unicast-udp-transport.cpp b/daemon/face/unicast-udp-transport.cpp
index c2c0d2b..a81e1d0 100644
--- a/daemon/face/unicast-udp-transport.cpp
+++ b/daemon/face/unicast-udp-transport.cpp
@@ -25,7 +25,7 @@
 
 #include "unicast-udp-transport.hpp"
 #include "udp-protocol.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #ifdef __linux__
 #include <cerrno>       // for errno
diff --git a/daemon/face/unix-stream-channel.cpp b/daemon/face/unix-stream-channel.cpp
index 52a4c99..4ef1a18 100644
--- a/daemon/face/unix-stream-channel.cpp
+++ b/daemon/face/unix-stream-channel.cpp
@@ -26,7 +26,7 @@
 #include "unix-stream-channel.hpp"
 #include "generic-link-service.hpp"
 #include "unix-stream-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <boost/filesystem.hpp>
 #include <sys/stat.h> // for chmod()
diff --git a/daemon/face/websocket-channel.cpp b/daemon/face/websocket-channel.cpp
index 74b4d39..f3f69ba 100644
--- a/daemon/face/websocket-channel.cpp
+++ b/daemon/face/websocket-channel.cpp
@@ -26,7 +26,7 @@
 #include "websocket-channel.hpp"
 #include "generic-link-service.hpp"
 #include "websocket-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/face/websocket-transport.cpp b/daemon/face/websocket-transport.cpp
index 63be570..d20e54c 100644
--- a/daemon/face/websocket-transport.cpp
+++ b/daemon/face/websocket-transport.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "websocket-transport.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace face {
diff --git a/daemon/fw/access-strategy.cpp b/daemon/fw/access-strategy.cpp
index 3b28246..59d99f3 100644
--- a/daemon/fw/access-strategy.cpp
+++ b/daemon/fw/access-strategy.cpp
@@ -25,8 +25,8 @@
 
 #include "access-strategy.hpp"
 #include "algorithm.hpp"
-#include "core/logger.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace fw {
diff --git a/daemon/fw/algorithm.hpp b/daemon/fw/algorithm.hpp
index 95d8bc5..07a0e01 100644
--- a/daemon/fw/algorithm.hpp
+++ b/daemon/fw/algorithm.hpp
@@ -26,7 +26,7 @@
 #ifndef NFD_DAEMON_FW_PIT_ALGORITHM_HPP
 #define NFD_DAEMON_FW_PIT_ALGORITHM_HPP
 
-#include "core/scope-prefix.hpp"
+#include "fw/scope-prefix.hpp"
 #include "table/fib.hpp"
 #include "table/pit-entry.hpp"
 
diff --git a/daemon/fw/asf-measurements.cpp b/daemon/fw/asf-measurements.cpp
index dde6866..404fc85 100644
--- a/daemon/fw/asf-measurements.cpp
+++ b/daemon/fw/asf-measurements.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "asf-measurements.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace fw {
diff --git a/daemon/fw/asf-probing-module.cpp b/daemon/fw/asf-probing-module.cpp
index 84055f1..46f1751 100644
--- a/daemon/fw/asf-probing-module.cpp
+++ b/daemon/fw/asf-probing-module.cpp
@@ -25,7 +25,7 @@
 
 #include "asf-probing-module.hpp"
 #include "algorithm.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <ndn-cxx/util/random.hpp>
 
diff --git a/daemon/fw/asf-strategy.cpp b/daemon/fw/asf-strategy.cpp
index e013fab..ce689bc 100644
--- a/daemon/fw/asf-strategy.cpp
+++ b/daemon/fw/asf-strategy.cpp
@@ -25,8 +25,8 @@
 
 #include "asf-strategy.hpp"
 #include "algorithm.hpp"
-#include "core/logger.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace fw {
diff --git a/daemon/fw/best-route-strategy2.cpp b/daemon/fw/best-route-strategy2.cpp
index 5c7d6a2..f2acfed 100644
--- a/daemon/fw/best-route-strategy2.cpp
+++ b/daemon/fw/best-route-strategy2.cpp
@@ -25,7 +25,7 @@
 
 #include "best-route-strategy2.hpp"
 #include "algorithm.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace fw {
diff --git a/daemon/fw/face-table.cpp b/daemon/fw/face-table.cpp
index a25e107..49d33b6 100644
--- a/daemon/fw/face-table.cpp
+++ b/daemon/fw/face-table.cpp
@@ -24,8 +24,8 @@
  */
 
 #include "face-table.hpp"
-#include "core/logger.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
 #include "face/channel.hpp"
 
 #include <ndn-cxx/util/concepts.hpp>
diff --git a/daemon/fw/forwarder-counters.hpp b/daemon/fw/forwarder-counters.hpp
index ca9eb4d..f526b86 100644
--- a/daemon/fw/forwarder-counters.hpp
+++ b/daemon/fw/forwarder-counters.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -26,7 +26,7 @@
 #ifndef NFD_DAEMON_FW_FORWARDER_COUNTERS_HPP
 #define NFD_DAEMON_FW_FORWARDER_COUNTERS_HPP
 
-#include "core/counter.hpp"
+#include "common/counter.hpp"
 
 namespace nfd {
 
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 328ff31..7a85daf 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -28,8 +28,8 @@
 #include "algorithm.hpp"
 #include "best-route-strategy2.hpp"
 #include "strategy.hpp"
-#include "core/logger.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
 #include "table/cleanup.hpp"
 
 #include <ndn-cxx/lp/tags.hpp>
diff --git a/daemon/fw/multicast-strategy.cpp b/daemon/fw/multicast-strategy.cpp
index f22514a..d15063e 100644
--- a/daemon/fw/multicast-strategy.cpp
+++ b/daemon/fw/multicast-strategy.cpp
@@ -25,7 +25,7 @@
 
 #include "multicast-strategy.hpp"
 #include "algorithm.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace fw {
diff --git a/daemon/fw/ncc-strategy.cpp b/daemon/fw/ncc-strategy.cpp
index 5063200..c427cd1 100644
--- a/daemon/fw/ncc-strategy.cpp
+++ b/daemon/fw/ncc-strategy.cpp
@@ -25,7 +25,7 @@
 
 #include "ncc-strategy.hpp"
 #include "algorithm.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 #include <ndn-cxx/util/random.hpp>
 
diff --git a/daemon/fw/process-nack-traits.cpp b/daemon/fw/process-nack-traits.cpp
index 4b2d091..6f3ad08 100644
--- a/daemon/fw/process-nack-traits.cpp
+++ b/daemon/fw/process-nack-traits.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "process-nack-traits.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace fw {
diff --git a/daemon/fw/scope-prefix.cpp b/daemon/fw/scope-prefix.cpp
new file mode 100644
index 0000000..984d19c
--- /dev/null
+++ b/daemon/fw/scope-prefix.cpp
@@ -0,0 +1,35 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "scope-prefix.hpp"
+
+namespace nfd {
+namespace scope_prefix {
+
+const Name LOCALHOST("ndn:/localhost");
+const Name LOCALHOP("ndn:/localhop");
+
+} // namespace scope_prefix
+} // namespace nfd
diff --git a/daemon/fw/scope-prefix.hpp b/daemon/fw/scope-prefix.hpp
new file mode 100644
index 0000000..265959d
--- /dev/null
+++ b/daemon/fw/scope-prefix.hpp
@@ -0,0 +1,64 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_FW_SCOPE_PREFIX_HPP
+#define NFD_DAEMON_FW_SCOPE_PREFIX_HPP
+
+#include "core/common.hpp"
+
+/** \brief contain name prefixes that affect namespace-based scope control
+ *  \sa https://redmine.named-data.net/projects/nfd/wiki/ScopeControl
+ */
+namespace nfd {
+namespace scope_prefix {
+
+/** \brief ndn:/localhost
+ *
+ *  The localhost scope limits propagation to the applications on the originating host.
+ *
+ *  Interest and Data packets under prefix ndn:/localhost are restricted by these rules:
+ *  \li Interest can come from and go to local faces only.
+ *  \li Data can come from and go to local faces only.
+ */
+extern const Name LOCALHOST;
+
+/** \brief ndn:/localhop
+ *
+ *  The localhop scope limits propagation to no further than the next node.
+ *
+ *  Interest packets under prefix ndn:/localhop are restricted by these rules:
+ *  \li If an Interest is received from a local face, it can be forwarded to a non-local face.
+ *  \li If an Interest is received from a non-local face, it cannot be forwarded to a non-local face.
+ *  \li In either case the Interest can be forwarded to a local face.
+ *  \li PIT entry can be satisfied by Data from any source.
+ *
+ *  Data packets under prefix ndn:/localhop are unrestricted.
+ */
+extern const Name LOCALHOP;
+
+} // namespace scope_prefix
+} // namespace nfd
+
+#endif // NFD_DAEMON_FW_SCOPE_PREFIX_HPP
diff --git a/daemon/fw/self-learning-strategy.cpp b/daemon/fw/self-learning-strategy.cpp
index d199b86..fd6d16e 100644
--- a/daemon/fw/self-learning-strategy.cpp
+++ b/daemon/fw/self-learning-strategy.cpp
@@ -26,8 +26,8 @@
 #include "self-learning-strategy.hpp"
 #include "algorithm.hpp"
 
-#include "core/logger.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
 #include "rib/service.hpp"
 
 #include <ndn-cxx/lp/empty-value.hpp>
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index 54574d7..151dac8 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -25,7 +25,7 @@
 
 #include "strategy.hpp"
 #include "forwarder.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 #include <boost/range/adaptor/map.hpp>
 #include <boost/range/algorithm/copy.hpp>
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 0675620..8a236ab 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -26,10 +26,10 @@
 #include "nfd.hpp"
 #include "rib/service.hpp"
 
-#include "core/logger.hpp"
-#include "core/privilege-helper.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
+#include "common/privilege-helper.hpp"
 #include "core/version.hpp"
-#include "daemon/global.hpp"
 
 #include <string.h> // for strsignal()
 
diff --git a/daemon/mgmt/command-authenticator.cpp b/daemon/mgmt/command-authenticator.cpp
index 913c74f..c146962 100644
--- a/daemon/mgmt/command-authenticator.cpp
+++ b/daemon/mgmt/command-authenticator.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "command-authenticator.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 #include <ndn-cxx/tag.hpp>
 #include <ndn-cxx/security/v2/certificate-fetcher-offline.hpp>
diff --git a/daemon/mgmt/command-authenticator.hpp b/daemon/mgmt/command-authenticator.hpp
index 5589187..9f136a8 100644
--- a/daemon/mgmt/command-authenticator.hpp
+++ b/daemon/mgmt/command-authenticator.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -26,7 +26,7 @@
 #ifndef NFD_DAEMON_MGMT_COMMAND_AUTHENTICATOR_HPP
 #define NFD_DAEMON_MGMT_COMMAND_AUTHENTICATOR_HPP
 
-#include "core/config-file.hpp"
+#include "common/config-file.hpp"
 
 #include <ndn-cxx/mgmt/dispatcher.hpp>
 
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index b7b22f2..9b36410 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -25,7 +25,7 @@
 
 #include "face-manager.hpp"
 
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 #include "face/generic-link-service.hpp"
 #include "face/protocol-factory.hpp"
 #include "fw/face-table.hpp"
diff --git a/daemon/mgmt/fib-manager.cpp b/daemon/mgmt/fib-manager.cpp
index 8fef3a3..1f0d173 100644
--- a/daemon/mgmt/fib-manager.cpp
+++ b/daemon/mgmt/fib-manager.cpp
@@ -25,7 +25,7 @@
 
 #include "fib-manager.hpp"
 
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 #include "fw/face-table.hpp"
 #include "table/fib.hpp"
 
@@ -66,7 +66,7 @@
     NFD_LOG_DEBUG("fib/add-nexthop(" << prefix << ',' << faceId << ',' << cost <<
                   "): FAIL prefix-too-long");
     return done(ControlResponse(414, "FIB entry prefix cannot exceed " +
-                                ndn::to_string(Fib::getMaxDepth()) + " components"));
+                                to_string(Fib::getMaxDepth()) + " components"));
   }
 
   Face* face = m_faceTable.get(faceId);
diff --git a/daemon/mgmt/general-config-section.cpp b/daemon/mgmt/general-config-section.cpp
index 732074b..de9c611 100644
--- a/daemon/mgmt/general-config-section.cpp
+++ b/daemon/mgmt/general-config-section.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "general-config-section.hpp"
-#include "core/privilege-helper.hpp"
+#include "common/privilege-helper.hpp"
 
 namespace nfd {
 namespace general {
diff --git a/daemon/mgmt/general-config-section.hpp b/daemon/mgmt/general-config-section.hpp
index a70bc48..cd9089d 100644
--- a/daemon/mgmt/general-config-section.hpp
+++ b/daemon/mgmt/general-config-section.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -23,10 +23,10 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef NFD_MGMT_GENERAL_CONFIG_SECTION_HPP
-#define NFD_MGMT_GENERAL_CONFIG_SECTION_HPP
+#ifndef NFD_DAEMON_MGMT_GENERAL_CONFIG_SECTION_HPP
+#define NFD_DAEMON_MGMT_GENERAL_CONFIG_SECTION_HPP
 
-#include "core/config-file.hpp"
+#include "common/config-file.hpp"
 
 namespace nfd {
 namespace general {
@@ -37,4 +37,4 @@
 } // namespace general
 } // namespace nfd
 
-#endif // NFD_MGMT_GENERAL_CONFIG_SECTION_HPP
+#endif // NFD_DAEMON_MGMT_GENERAL_CONFIG_SECTION_HPP
diff --git a/daemon/mgmt/log-config-section.cpp b/daemon/mgmt/log-config-section.cpp
new file mode 100644
index 0000000..9d8168c
--- /dev/null
+++ b/daemon/mgmt/log-config-section.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "log-config-section.hpp"
+
+#include <ndn-cxx/util/logger.hpp>
+#include <ndn-cxx/util/logging.hpp>
+
+namespace nfd {
+namespace log {
+
+static ndn::util::LogLevel
+parseLogLevel(const ConfigSection& item, const std::string& key)
+{
+  try {
+    return ndn::util::parseLogLevel(item.get_value<std::string>());
+  }
+  catch (const std::invalid_argument&) {
+    NDN_THROW_NESTED(ConfigFile::Error("Invalid log level for '" + key + "' in section 'log'"));
+  }
+}
+
+static void
+onConfig(const ConfigSection& section, bool isDryRun, const std::string&)
+{
+  // log
+  // {
+  //   ; default_level specifies the logging level for modules
+  //   ; that are not explicitly named. All debugging levels
+  //   ; listed above the selected value are enabled.
+  //
+  //   default_level INFO
+  //
+  //   ; You may also override the default for specific modules:
+  //
+  //   FibManager DEBUG
+  //   Forwarder WARN
+  // }
+
+  auto defaultLevel = ndn::util::LogLevel::INFO;
+  auto item = section.get_child_optional("default_level");
+  if (item) {
+    defaultLevel = parseLogLevel(*item, "default_level");
+  }
+  if (!isDryRun) {
+    // default_level applies only to NFD loggers
+    ndn::util::Logging::setLevel("nfd.*", defaultLevel);
+  }
+
+  for (const auto& i : section) {
+    if (i.first == "default_level") {
+      // do nothing
+    }
+    else {
+      auto level = parseLogLevel(i.second, i.first);
+      if (!isDryRun) {
+        if (i.first.find('.') == std::string::npos)
+          // backward compat: assume unqualified logger names refer to NFD loggers
+          ndn::util::Logging::setLevel("nfd." + i.first, level);
+        else
+          ndn::util::Logging::setLevel(i.first, level);
+      }
+    }
+  }
+}
+
+void
+setConfigFile(ConfigFile& config)
+{
+  config.addSectionHandler("log", &onConfig);
+}
+
+} // namespace log
+} // namespace nfd
diff --git a/daemon/mgmt/log-config-section.hpp b/daemon/mgmt/log-config-section.hpp
new file mode 100644
index 0000000..e7e4022
--- /dev/null
+++ b/daemon/mgmt/log-config-section.hpp
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_MGMT_LOG_CONFIG_SECTION_HPP
+#define NFD_DAEMON_MGMT_LOG_CONFIG_SECTION_HPP
+
+#include "common/config-file.hpp"
+
+namespace nfd {
+namespace log {
+
+void
+setConfigFile(ConfigFile& config);
+
+} // namespace log
+} // namespace nfd
+
+#endif // NFD_DAEMON_MGMT_LOG_CONFIG_SECTION_HPP
diff --git a/daemon/mgmt/rib-manager.cpp b/daemon/mgmt/rib-manager.cpp
index a790775..383c47f 100644
--- a/daemon/mgmt/rib-manager.cpp
+++ b/daemon/mgmt/rib-manager.cpp
@@ -25,10 +25,10 @@
 
 #include "rib-manager.hpp"
 
-#include "core/fib-max-depth.hpp"
-#include "core/logger.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
 #include "rib/rib.hpp"
+#include "table/fib.hpp"
 
 #include <ndn-cxx/lp/tags.hpp>
 #include <ndn-cxx/mgmt/nfd/face-status.hpp>
@@ -217,8 +217,8 @@
                           ControlParameters parameters,
                           const ndn::mgmt::CommandContinuation& done)
 {
-  if (parameters.getName().size() > FIB_MAX_DEPTH) {
-    done(ControlResponse(414, "Route prefix cannot exceed " + ndn::to_string(FIB_MAX_DEPTH) +
+  if (parameters.getName().size() > Fib::getMaxDepth()) {
+    done(ControlResponse(414, "Route prefix cannot exceed " + to_string(Fib::getMaxDepth()) +
                               " components"));
     return;
   }
diff --git a/daemon/mgmt/rib-manager.hpp b/daemon/mgmt/rib-manager.hpp
index 6888024..a5e663f 100644
--- a/daemon/mgmt/rib-manager.hpp
+++ b/daemon/mgmt/rib-manager.hpp
@@ -27,7 +27,6 @@
 #define NFD_DAEMON_MGMT_RIB_MANAGER_HPP
 
 #include "manager-base.hpp"
-#include "core/config-file.hpp"
 #include "rib/route.hpp"
 
 #include <ndn-cxx/mgmt/nfd/controller.hpp>
diff --git a/daemon/mgmt/strategy-choice-manager.cpp b/daemon/mgmt/strategy-choice-manager.cpp
index bebe1a0..169ce2e 100644
--- a/daemon/mgmt/strategy-choice-manager.cpp
+++ b/daemon/mgmt/strategy-choice-manager.cpp
@@ -25,7 +25,7 @@
 
 #include "strategy-choice-manager.hpp"
 
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 #include "table/strategy-choice.hpp"
 
 #include <ndn-cxx/mgmt/nfd/strategy-choice.hpp>
diff --git a/daemon/mgmt/tables-config-section.hpp b/daemon/mgmt/tables-config-section.hpp
index 932df2c..c2cfec5 100644
--- a/daemon/mgmt/tables-config-section.hpp
+++ b/daemon/mgmt/tables-config-section.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -23,11 +23,11 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef NFD_MGMT_TABLES_CONFIG_SECTION_HPP
-#define NFD_MGMT_TABLES_CONFIG_SECTION_HPP
+#ifndef NFD_DAEMON_MGMT_TABLES_CONFIG_SECTION_HPP
+#define NFD_DAEMON_MGMT_TABLES_CONFIG_SECTION_HPP
 
+#include "common/config-file.hpp"
 #include "fw/forwarder.hpp"
-#include "core/config-file.hpp"
 
 namespace nfd {
 
@@ -101,4 +101,4 @@
 
 } // namespace nfd
 
-#endif // NFD_MGMT_TABLES_CONFIG_SECTION_HPP
+#endif // NFD_DAEMON_MGMT_TABLES_CONFIG_SECTION_HPP
diff --git a/daemon/nfd.cpp b/daemon/nfd.cpp
index 078d987..a615563 100644
--- a/daemon/nfd.cpp
+++ b/daemon/nfd.cpp
@@ -24,10 +24,9 @@
  */
 
 #include "nfd.hpp"
-#include "global.hpp"
-#include "core/config-file.hpp"
-#include "core/log-config-section.hpp"
-#include "core/privilege-helper.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
+#include "common/privilege-helper.hpp"
 #include "face/face-system.hpp"
 #include "face/internal-face.hpp"
 #include "face/null-face.hpp"
@@ -37,6 +36,7 @@
 #include "mgmt/fib-manager.hpp"
 #include "mgmt/forwarder-status-manager.hpp"
 #include "mgmt/general-config-section.hpp"
+#include "mgmt/log-config-section.hpp"
 #include "mgmt/strategy-choice-manager.hpp"
 #include "mgmt/tables-config-section.hpp"
 
diff --git a/daemon/nfd.hpp b/daemon/nfd.hpp
index ba8efd4..f0a09f4 100644
--- a/daemon/nfd.hpp
+++ b/daemon/nfd.hpp
@@ -26,7 +26,7 @@
 #ifndef NFD_DAEMON_NFD_HPP
 #define NFD_DAEMON_NFD_HPP
 
-#include "core/config-file.hpp"
+#include "common/config-file.hpp"
 
 #include <ndn-cxx/net/network-monitor.hpp>
 #include <ndn-cxx/security/key-chain.hpp>
diff --git a/daemon/rib/fib-updater.cpp b/daemon/rib/fib-updater.cpp
index 574b5f9..2ee14fd 100644
--- a/daemon/rib/fib-updater.cpp
+++ b/daemon/rib/fib-updater.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "fib-updater.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 #include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
 
diff --git a/daemon/rib/readvertise/host-to-gateway-readvertise-policy.cpp b/daemon/rib/readvertise/host-to-gateway-readvertise-policy.cpp
index 7810619..9ee7985 100644
--- a/daemon/rib/readvertise/host-to-gateway-readvertise-policy.cpp
+++ b/daemon/rib/readvertise/host-to-gateway-readvertise-policy.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "host-to-gateway-readvertise-policy.hpp"
-#include "core/scope-prefix.hpp"
+#include "fw/scope-prefix.hpp"
 #include "mgmt/rib-manager.hpp"
 
 #include <ndn-cxx/security/pib/identity.hpp>
diff --git a/daemon/rib/readvertise/host-to-gateway-readvertise-policy.hpp b/daemon/rib/readvertise/host-to-gateway-readvertise-policy.hpp
index 69e914a..325fc80 100644
--- a/daemon/rib/readvertise/host-to-gateway-readvertise-policy.hpp
+++ b/daemon/rib/readvertise/host-to-gateway-readvertise-policy.hpp
@@ -27,7 +27,7 @@
 #define NFD_DAEMON_RIB_READVERTISE_HOST_TO_GATEWAY_READVERTISE_POLICY_HPP
 
 #include "readvertise-policy.hpp"
-#include "core/config-file.hpp"
+#include "common/config-file.hpp"
 
 #include <ndn-cxx/security/key-chain.hpp>
 
diff --git a/daemon/rib/readvertise/nfd-rib-readvertise-destination.cpp b/daemon/rib/readvertise/nfd-rib-readvertise-destination.cpp
index f0a0482..a76aaed 100644
--- a/daemon/rib/readvertise/nfd-rib-readvertise-destination.cpp
+++ b/daemon/rib/readvertise/nfd-rib-readvertise-destination.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,7 +24,7 @@
  */
 
 #include "nfd-rib-readvertise-destination.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 #include <ndn-cxx/mgmt/nfd/control-command.hpp>
 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
diff --git a/daemon/rib/readvertise/readvertise-destination.cpp b/daemon/rib/readvertise/readvertise-destination.cpp
index a687a8a..972c1dc 100644
--- a/daemon/rib/readvertise/readvertise-destination.cpp
+++ b/daemon/rib/readvertise/readvertise-destination.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,7 +24,7 @@
  */
 
 #include "readvertise-destination.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace rib {
diff --git a/daemon/rib/readvertise/readvertise.cpp b/daemon/rib/readvertise/readvertise.cpp
index 7b59e22..2f16795 100644
--- a/daemon/rib/readvertise/readvertise.cpp
+++ b/daemon/rib/readvertise/readvertise.cpp
@@ -24,8 +24,8 @@
  */
 
 #include "readvertise.hpp"
-#include "core/logger.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
 
 #include <ndn-cxx/util/random.hpp>
 
diff --git a/daemon/rib/rib-entry.cpp b/daemon/rib/rib-entry.cpp
index 008ac4f..7385d16 100644
--- a/daemon/rib/rib-entry.cpp
+++ b/daemon/rib/rib-entry.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,7 +24,7 @@
  */
 
 #include "rib-entry.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 #include <ndn-cxx/mgmt/nfd/control-command.hpp>
 
diff --git a/daemon/rib/rib.cpp b/daemon/rib/rib.cpp
index bbd72f1..1491c87 100644
--- a/daemon/rib/rib.cpp
+++ b/daemon/rib/rib.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -25,7 +25,7 @@
 
 #include "rib.hpp"
 #include "fib-updater.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace rib {
diff --git a/daemon/rib/service.cpp b/daemon/rib/service.cpp
index 043b980..564e3d6 100644
--- a/daemon/rib/service.cpp
+++ b/daemon/rib/service.cpp
@@ -31,8 +31,8 @@
 #include "readvertise/nfd-rib-readvertise-destination.hpp"
 #include "readvertise/readvertise.hpp"
 
-#include "core/logger.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
 
 #include <boost/property_tree/info_parser.hpp>
 #include <ndn-cxx/transport/tcp-transport.hpp>
diff --git a/daemon/rib/service.hpp b/daemon/rib/service.hpp
index d1c2226..ca5f57b 100644
--- a/daemon/rib/service.hpp
+++ b/daemon/rib/service.hpp
@@ -26,7 +26,7 @@
 #ifndef NFD_DAEMON_RIB_SERVICE_HPP
 #define NFD_DAEMON_RIB_SERVICE_HPP
 
-#include "core/config-file.hpp"
+#include "common/config-file.hpp"
 #include "mgmt/rib-manager.hpp"
 #include "rib/fib-updater.hpp"
 #include "rib/rib.hpp"
diff --git a/daemon/table/cs-policy-priority-fifo.cpp b/daemon/table/cs-policy-priority-fifo.cpp
index f350c72..db13013 100644
--- a/daemon/table/cs-policy-priority-fifo.cpp
+++ b/daemon/table/cs-policy-priority-fifo.cpp
@@ -25,7 +25,7 @@
 
 #include "cs-policy-priority-fifo.hpp"
 #include "cs.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace cs {
diff --git a/daemon/table/cs-policy.cpp b/daemon/table/cs-policy.cpp
index a982590..4930af8 100644
--- a/daemon/table/cs-policy.cpp
+++ b/daemon/table/cs-policy.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -25,7 +25,7 @@
 
 #include "cs-policy.hpp"
 #include "cs.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 #include <boost/range/adaptor/map.hpp>
 #include <boost/range/algorithm/copy.hpp>
diff --git a/daemon/table/cs.cpp b/daemon/table/cs.cpp
index a958374..3a06c7d 100644
--- a/daemon/table/cs.cpp
+++ b/daemon/table/cs.cpp
@@ -24,8 +24,8 @@
  */
 
 #include "cs.hpp"
+#include "common/logger.hpp"
 #include "core/algorithm.hpp"
-#include "core/logger.hpp"
 
 #include <ndn-cxx/lp/tags.hpp>
 #include <ndn-cxx/util/concepts.hpp>
diff --git a/daemon/table/dead-nonce-list.cpp b/daemon/table/dead-nonce-list.cpp
index 7d6a908..3521b51 100644
--- a/daemon/table/dead-nonce-list.cpp
+++ b/daemon/table/dead-nonce-list.cpp
@@ -24,9 +24,9 @@
  */
 
 #include "dead-nonce-list.hpp"
-#include "core/city-hash.hpp"
-#include "core/logger.hpp"
-#include "daemon/global.hpp"
+#include "common/city-hash.hpp"
+#include "common/global.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 
diff --git a/daemon/table/fib.hpp b/daemon/table/fib.hpp
index fc73a7d..462a29b 100644
--- a/daemon/table/fib.hpp
+++ b/daemon/table/fib.hpp
@@ -29,8 +29,6 @@
 #include "fib-entry.hpp"
 #include "name-tree.hpp"
 
-#include "core/fib-max-depth.hpp"
-
 #include <boost/range/adaptor/transformed.hpp>
 
 namespace nfd {
@@ -89,7 +87,7 @@
   static constexpr size_t
   getMaxDepth()
   {
-    return FIB_MAX_DEPTH;
+    return NameTree::getMaxDepth();
   }
 
   /** \brief Find or insert a FIB entry
diff --git a/daemon/table/measurements.cpp b/daemon/table/measurements.cpp
index adfd782..af3cc1e 100644
--- a/daemon/table/measurements.cpp
+++ b/daemon/table/measurements.cpp
@@ -27,7 +27,7 @@
 #include "name-tree.hpp"
 #include "pit-entry.hpp"
 #include "fib-entry.hpp"
-#include "daemon/global.hpp"
+#include "common/global.hpp"
 
 namespace nfd {
 namespace measurements {
diff --git a/daemon/table/name-tree-hashtable.cpp b/daemon/table/name-tree-hashtable.cpp
index 2e25223..7d20a34 100644
--- a/daemon/table/name-tree-hashtable.cpp
+++ b/daemon/table/name-tree-hashtable.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,8 +24,8 @@
  */
 
 #include "name-tree-hashtable.hpp"
-#include "core/city-hash.hpp"
-#include "core/logger.hpp"
+#include "common/city-hash.hpp"
+#include "common/logger.hpp"
 
 namespace nfd {
 namespace name_tree {
diff --git a/daemon/table/name-tree-iterator.cpp b/daemon/table/name-tree-iterator.cpp
index f295d9c..33b5382 100644
--- a/daemon/table/name-tree-iterator.cpp
+++ b/daemon/table/name-tree-iterator.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018,  Regents of the University of California,
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -25,7 +25,7 @@
 
 #include "name-tree-iterator.hpp"
 #include "name-tree.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 #include <boost/range/concepts.hpp>
 #include <ndn-cxx/util/concepts.hpp>
diff --git a/daemon/table/name-tree.cpp b/daemon/table/name-tree.cpp
index 3eca24f..aac885c 100644
--- a/daemon/table/name-tree.cpp
+++ b/daemon/table/name-tree.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "name-tree.hpp"
-#include "core/logger.hpp"
+#include "common/logger.hpp"
 
 #include <boost/concept/assert.hpp>
 #include <boost/concept_check.hpp>
diff --git a/daemon/table/name-tree.hpp b/daemon/table/name-tree.hpp
index 1cb5f31..b3c7da4 100644
--- a/daemon/table/name-tree.hpp
+++ b/daemon/table/name-tree.hpp
@@ -28,8 +28,6 @@
 
 #include "name-tree-iterator.hpp"
 
-#include "core/fib-max-depth.hpp"
-
 namespace nfd {
 namespace name_tree {
 
@@ -52,7 +50,7 @@
   static constexpr size_t
   getMaxDepth()
   {
-    return FIB_MAX_DEPTH;
+    return 32;
   }
 
   /** \return number of name tree entries
diff --git a/daemon/table/strategy-choice.cpp b/daemon/table/strategy-choice.cpp
index b6cb0f7..e03306c 100644
--- a/daemon/table/strategy-choice.cpp
+++ b/daemon/table/strategy-choice.cpp
@@ -24,10 +24,10 @@
  */
 
 #include "strategy-choice.hpp"
-
 #include "measurements-entry.hpp"
 #include "pit-entry.hpp"
-#include "core/logger.hpp"
+
+#include "common/logger.hpp"
 #include "fw/strategy.hpp"
 
 #include <ndn-cxx/util/concepts.hpp>