net: add NetworkAddress::isDeprecated() helper function

Change-Id: I869bfc9272744211fff00729c6783874f518a4b5
diff --git a/ndn-cxx/net/impl/network-monitor-impl-netlink.cpp b/ndn-cxx/net/impl/network-monitor-impl-netlink.cpp
index 1137992..0862371 100644
--- a/ndn-cxx/net/impl/network-monitor-impl-netlink.cpp
+++ b/ndn-cxx/net/impl/network-monitor-impl-netlink.cpp
@@ -363,7 +363,7 @@
     flags = *extFlags;
 #endif // NDN_CXX_HAVE_IFA_FLAGS
 
-  if (flags & IFA_F_TENTATIVE) {
+  if ((flags & IFA_F_TENTATIVE) && nlmsg->nlmsg_type == RTM_NEWADDR) {
     // https://redmine.named-data.net/issues/5155#note-10
     NDN_LOG_DEBUG("  ignoring tentative address " << ipAddr);
     return;
diff --git a/ndn-cxx/net/network-address.cpp b/ndn-cxx/net/network-address.cpp
index a15c939..f8e8a6e 100644
--- a/ndn-cxx/net/network-address.cpp
+++ b/ndn-cxx/net/network-address.cpp
@@ -23,6 +23,10 @@
 
 #include "ndn-cxx/net/network-address.hpp"
 
+#ifdef __linux__
+#include <linux/if_addr.h>
+#endif
+
 namespace ndn {
 namespace net {
 
@@ -57,6 +61,18 @@
 {
 }
 
+bool
+NetworkAddress::isDeprecated() const
+{
+#ifdef __linux__
+  return m_flags & IFA_F_DEPRECATED;
+#else
+  // should probably check for IN6_IFF_DEPRECATED on macOS and FreeBSD, but the
+  // NetworkMonitor backend for those platforms doesn't provide any address flags
+  return false;
+#endif
+}
+
 std::ostream&
 operator<<(std::ostream& os, const NetworkAddress& addr)
 {
diff --git a/ndn-cxx/net/network-address.hpp b/ndn-cxx/net/network-address.hpp
index 4d46374..1bb435c 100644
--- a/ndn-cxx/net/network-address.hpp
+++ b/ndn-cxx/net/network-address.hpp
@@ -60,7 +60,8 @@
                  AddressScope scope,
                  uint32_t flags);
 
-  /** @brief Returns the address family
+  /**
+   * @brief Returns the address family
    */
   AddressFamily
   getFamily() const
@@ -68,7 +69,8 @@
     return m_family;
   }
 
-  /** @brief Returns the IP address (v4 or v6)
+  /**
+   * @brief Returns the IP address (v4 or v6)
    */
   boost::asio::ip::address
   getIp() const
@@ -76,7 +78,8 @@
     return m_ip;
   }
 
-  /** @brief Returns the IP broadcast address
+  /**
+   * @brief Returns the IP broadcast address
    */
   boost::asio::ip::address
   getBroadcast() const
@@ -84,7 +87,8 @@
     return m_broadcast;
   }
 
-  /** @brief Returns the prefix length
+  /**
+   * @brief Returns the prefix length
    */
   uint8_t
   getPrefixLength() const
@@ -92,7 +96,8 @@
     return m_prefixLength;
   }
 
-  /** @brief Returns the address scope
+  /**
+   * @brief Returns the address scope
    */
   AddressScope
   getScope() const
@@ -100,7 +105,8 @@
     return m_scope;
   }
 
-  /** @brief Returns a bitset of platform-specific flags enabled on the address
+  /**
+   * @brief Returns a bitset of platform-specific flags enabled on the address
    */
   uint32_t
   getFlags() const
@@ -108,6 +114,14 @@
     return m_flags;
   }
 
+  /**
+   * @brief Returns true if the address is deprecated
+   * @sa RFC 4862
+   * @note Currently implemented only on Linux. Always returns false on other platforms.
+   */
+  bool
+  isDeprecated() const;
+
   friend bool
   operator<(const NetworkAddress& a, const NetworkAddress& b)
   {
@@ -120,7 +134,7 @@
   boost::asio::ip::address m_broadcast;
   uint8_t m_prefixLength;
   AddressScope m_scope;
-  uint32_t m_flags; // IFA_F_* in if_addr.h
+  uint32_t m_flags; // IFA_F_* (linux/if_addr.h) on Linux; zero on other platforms
 };
 
 std::ostream&
diff --git a/ndn-cxx/net/network-interface.cpp b/ndn-cxx/net/network-interface.cpp
index d7a5e7f..2adf2ef 100644
--- a/ndn-cxx/net/network-interface.cpp
+++ b/ndn-cxx/net/network-interface.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2021 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -228,9 +228,14 @@
 
   for (const auto& addr : netif.getNetworkAddresses()) {
     os << "    " << (addr.getFamily() == AddressFamily::V4 ? "inet " : "inet6 ") << addr;
-    if (netif.canBroadcast() && !addr.getBroadcast().is_unspecified())
+    if (netif.canBroadcast() && !addr.getBroadcast().is_unspecified()) {
       os << " brd " << addr.getBroadcast();
-    os << " scope " << addr.getScope() << "\n";
+    }
+    os << " scope " << addr.getScope();
+    if (addr.isDeprecated()) {
+      os << " deprecated";
+    }
+    os << "\n";
   }
 
   return os;
diff --git a/tests/integration/network-monitor.README.md b/tests/integration/network-monitor.README.md
index 7b339c0..0e5b5ad 100644
--- a/tests/integration/network-monitor.README.md
+++ b/tests/integration/network-monitor.README.md
@@ -1,12 +1,13 @@
-# NetworkMonitor test
+# Testing NetworkMonitor functionality
 
-These instructions are only for Linux and macOS.
+> These instructions are only for Linux and macOS.
 
 Run the network-monitor integration test binary, e.g.:
-```
+
+```sh
+# sudo not required
 ./build/tests/integration/network-monitor
 ```
-Note: sudo is not required.
 
 You should see an `onInterfaceAdded` message for each ethernet and loopback
 network interface present on the system, followed by an `onAddressAdded`
@@ -16,9 +17,9 @@
 
 ## Linux
 
-[The following commands assume eth0 is the name of an ethernet interface
-on the machine. If your interfaces are named differently, replace eth0
-with the name of any ethernet interface that you have available.]
+The following commands assume `eth0` is the name of an ethernet interface
+on the machine. If your interfaces are named differently, replace `eth0`
+with the name of any ethernet interface that you have available.
 
 Command | Expected output
 --------|----------------
@@ -32,12 +33,14 @@
 sudo ip link delete dev nmtest0 | `nmtest0: onInterfaceRemoved`
 
 If you unplug the ethernet cable from your network card, you should see:
+
 ```
 eth0: onStateChanged running -> no-carrier
 nmtest0: onStateChanged running -> no-carrier
 ```
 
 Plugging the cable back in should produce the following messages:
+
 ```
 eth0: onStateChanged no-carrier -> running
 nmtest0: onStateChanged no-carrier -> running
@@ -45,9 +48,9 @@
 
 ## macOS
 
-[The following commands assume en0 is the name of an ethernet interface
-on the machine. If your interfaces are named differently, replace en0
-with the name of any ethernet interface that you have available.]
+The following commands assume `en0` is the name of an ethernet interface
+on the machine. If your interfaces are named differently, replace `en0`
+with the name of any ethernet interface that you have available.
 
 Command | Expected output
 --------|----------------
@@ -60,11 +63,13 @@
 sudo ifconfig vlan1 destroy | `vlan1: onInterfaceRemoved`
 
 If you unplug the ethernet cable from your network card, you should see:
+
 ```
 en6: onStateChanged running -> down
 ```
 
 Plugging the cable back in should produce the following messages:
+
 ```
 en6: onStateChanged down -> running
 ```