Project

General

Profile

Actions

Feature #3353

closed

NetworkMonitor: emit fine-grained signals when the state of a network interface changes

Added by Andrea Tosatto over 8 years ago. Updated almost 7 years ago.

Status:
Closed
Priority:
Normal
Category:
Utils
Target version:
Start date:
Due date:
% Done:

100%

Estimated time:

Description

Save the status of every system network interface and notify if there are any link or address changes in one of them. For example:

  • eth0 is unplugged -> emit an interface removal signal
  • wlan0 is down -> emit an internal state change signal
  • wlan1 has a new IP address -> emit an IP address addition signal

Related issues 6 (1 open5 closed)

Blocks NFD - Feature #3352: Set transport state UP/DOWN based on the state of the underlying network interfaceIn Progress

Actions
Blocks NFD - Feature #3257: EthernetTransport: support runtime MTU changesClosedEric Newberry

Actions
Blocks ndn-cxx - Feature #3817: NetworkMonitor fine-grained signals for macOSClosedDavide Pesavento03/25/2017

Actions
Blocks NFD - Feature #4021: FaceSystem: use NetworkMonitor::listNetworkInterfaces()ClosedJunxiao Shi

Actions
Blocks ndn-cxx - Feature #4024: NetworkMonitor: stub implementationClosedJunxiao Shi

Actions
Blocks ndn-cxx - Feature #4025: NetworkMonitor: empty impl on unsupported platformClosedJunxiao Shi

Actions
Actions #1

Updated by Andrea Tosatto over 8 years ago

  • Status changed from New to In Progress

The idea is to add a fine grained monitoring of all the network interfaces in the ndn::util::NetworkMonitor class.

Save the list of all the networks interfaces using a map would be easier to answer requests about the state of one or more interfaces. Every map element will be of type NetworkInterfaceInfo declared inside nfd::NetworkInterface. This is a class used in NFD and useful to store a single network interface state. The NetworkInterfaceInfo will be copied inside NetworkMonitor and later can be removed from NFD.

NetworkMonitor will update asynchronously the map and send a signal according to the event.

As part of this task I'll implement the class only for linux and will rely on rtnetlink notifications to detect changes in the host network configuration.

To be more clear you can find my proposed new header here:
https://gist.github.com/andreatosatto90/07d35be01ecfa50df083

Actions #2

Updated by Davide Pesavento over 8 years ago

  • Tracker changed from Task to Feature
Actions #3

Updated by Junxiao Shi over 8 years ago

  • Parent task deleted (#3352)
Actions #4

Updated by Junxiao Shi over 8 years ago

  • Blocks Feature #3352: Set transport state UP/DOWN based on the state of the underlying network interface added
Actions #5

Updated by Davide Pesavento over 8 years ago

  • Subject changed from NetworkMonitor: emit signal when the state of a network interface changes to NetworkMonitor: emit fine-grained signals when the state of a network interface changes
  • Description updated (diff)
  • Start date deleted (11/26/2015)
Actions #6

Updated by Andrea Tosatto about 8 years ago

  • % Done changed from 0 to 70
Actions #7

Updated by Davide Pesavento about 8 years ago

  • Status changed from In Progress to Code review
  • % Done changed from 70 to 90
Actions #8

Updated by Davide Pesavento about 8 years ago

  • Blocks Feature #3257: EthernetTransport: support runtime MTU changes added
Actions #9

Updated by Davide Pesavento about 8 years ago

Actions #10

Updated by Junxiao Shi almost 8 years ago

  • Status changed from Code review to Feedback
  • Assignee deleted (Andrea Tosatto)
  • % Done changed from 90 to 50

There has been an incomplete submission in http://gerrit.named-data.net/2708, but Andrea is gone so someone else needs to finish it.

Actions #11

Updated by Junxiao Shi almost 8 years ago

  • Target version deleted (v0.5)

20160719 call decides @Davide is responsible for finding a new assignee.

Actions #12

Updated by Jeff Burke over 7 years ago

  • Priority changed from Normal to High

This is very important for demonstrating robustness.

Actions #13

Updated by Junxiao Shi over 7 years ago

  • Assignee set to Weiwei Liu
  • Priority changed from High to Normal
  • Target version set to v0.6
Actions #14

Updated by Jeff Burke over 7 years ago

Why did the priority for this issue get lowered? It remains important to the application team for trying to make field deployments of NDN more resilient to connectivity changes. Needs to target v0.5 of dependent Feature #3521.

Actions #15

Updated by Junxiao Shi over 7 years ago

  • Description updated (diff)
  • Estimated time set to 6.00 h

Since the implementation is platform specific, we should finalize the Linux implementation within this issue. macOS platform implementation is split into #3817.

Actions #16

Updated by Junxiao Shi over 7 years ago

  • Blocks Feature #3817: NetworkMonitor fine-grained signals for macOS added
Actions #17

Updated by Junxiao Shi over 7 years ago

  • Priority changed from Normal to High
Actions #18

Updated by Davide Pesavento over 7 years ago

  • Status changed from Feedback to In Progress
Actions #19

Updated by Alex Afanasyev about 7 years ago

  • Assignee deleted (Weiwei Liu)
Actions #20

Updated by Alex Afanasyev about 7 years ago

  • Assignee set to Davide Pesavento
  • Priority changed from High to Normal
Actions #21

Updated by Alex Afanasyev about 7 years ago

  • % Done changed from 50 to 90
Actions #22

Updated by Alex Afanasyev about 7 years ago

  • Status changed from In Progress to Code review
Actions #23

Updated by Junxiao Shi about 7 years ago

Actions #24

Updated by Junxiao Shi about 7 years ago

  • Blocks Feature #4021: FaceSystem: use NetworkMonitor::listNetworkInterfaces() added
Actions #25

Updated by Junxiao Shi about 7 years ago

what would be the criteria to test this and the other patch? Just run integration test and observe that information is being properly updated?
NetworkMonitor itself is intrinsically not unit-testable. On the other hand, NetworkAddress and NetworkInterface could be unit tested.

This can be structured as a "manual test". A document should be placed at tests/integrated/network-monitor.txt, which looks like:

  1. start build/tests/integrated/network-monitor program
  2. execute ip link add link eth0 name eth0-1, NM should output "[eth0-1] onInterfaceAdded"
  3. execute ip addr 192.168.7.2/24 dev eth0-1, NM should output "[eth0-1] onAddressAdded 192.168.7.2/24"
  4. unplug the Ethernet cord on eth1 interface, NM should output "[eth1] onStateChanged no-carrier"

The steps may require the use of USB Ethernet adapters, WiFi interfaces, etc. Any step may be skipped if equipment is unavailable.
This allows anyone to test the program manually, given they have the right equipment. Compared to not providing this document, this removes the uncertainty on what would be the correct behavior given a certain action.

Actions #26

Updated by Junxiao Shi about 7 years ago

  • Blocks Feature #4024: NetworkMonitor: stub implementation added
Actions #27

Updated by Junxiao Shi about 7 years ago

  • Blocks Feature #4025: NetworkMonitor: empty impl on unsupported platform added
Actions #28

Updated by Junxiao Shi about 7 years ago

On Ubuntu 16.04 32-bit, http://gerrit.named-data.net/2708 patchset29 crashes if NetworkMonitor is destructed before onEnumerationCompleted is invoked.

// g++ -std=c++11 -o x x.cpp $(pkg-config --cflags --libs libndn-cxx)

#include <boost/asio.hpp>
#include <ndn-cxx/util/network-interface.hpp>

int
main()
{
  boost::asio::io_service io;
  std::unique_ptr<ndn::util::NetworkMonitor> nm(new ndn::util::NetworkMonitor(io));
  nm->onInterfaceAdded.connect([&] (std::shared_ptr<ndn::util::NetworkInterface>) {
    io.post([&] {
      nm.reset();
    });
  });
  io.run();
}
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<ndn::util::NetworkMonitor::Error> >'
  what():  Netlink socket read failed (Bad file descriptor)

Thread 1 "x" received signal SIGABRT, Aborted.
0xb7fdac31 in __kernel_vsyscall ()
(gdb) bt full
#0  0xb7fdac31 in __kernel_vsyscall ()
No symbol table info available.
#1  0xb7b8cea9 in __GI_raise (sig=6) at ../sysdeps/unix/sysv/linux/raise.c:54
        resultvar = <optimized out>
        resultvar = <optimized out>
        pid = 27239
        selftid = 27239
#2  0xb7b8e407 in __GI_abort () at abort.c:89
        save_stage = 2
        act = {__sigaction_handler = {sa_handler = 0xb7d3dfec, 
            sa_sigaction = 0xb7d3dfec}, sa_mask = {__val = {5, 3086997664, 
              3086895472, 3084112684, 5, 3086997664, 3085598748, 3086915490, 
              3086998104, 3081672512, 1, 5, 0, 3083939840, 3087003648, 
              3084198700, 3083943104, 3082577437, 3087003648, 3084198700, 48, 
              3084536027, 3086915307, 3082187192, 3083943416, 135031812, 
              3086915307, 3085598720, 3083943416, 135031812, 3221222088, 
              3086941968}}, sa_flags = 135031888, 
          sa_restorer = 0xb7b8e2b0 <__GI_abort>}
        sigs = {__val = {32, 0 <repeats 31 times>}}
#3  0xb7da7d35 in __gnu_cxx::__verbose_terminate_handler() ()
   from /usr/lib/i386-linux-gnu/libstdc++.so.6
No symbol table info available.
#4  0xb7da5833 in ?? () from /usr/lib/i386-linux-gnu/libstdc++.so.6
---Type <return> to continue, or q <return> to quit---
No symbol table info available.
#5  0xb7da58ad in std::terminate() ()
   from /usr/lib/i386-linux-gnu/libstdc++.so.6
No symbol table info available.
#6  0xb7da5b70 in __cxa_throw () from /usr/lib/i386-linux-gnu/libstdc++.so.6
No symbol table info available.
#7  0x08070331 in boost::throw_exception<boost::exception_detail::error_info_injector<ndn::util::NetworkMonitor::Error> > (e=...)
    at /usr/include/boost/throw_exception.hpp:69
No locals.
#8  0x08070412 in boost::exception_detail::throw_exception_<ndn::util::NetworkMonitor::Error> (x=..., 
    current_function=0x809e880 <ndn::util::NetworkMonitor::Impl::onReceiveRtnl(boost::system::error_code const&, unsigned int)::__PRETTY_FUNCTION__> "void ndn::util::NetworkMonitor::Impl::onReceiveRtnl(const boost::system::error_code&, size_t)", file=0x809e310 "../src/util/detail/network-monitor-impl-rtnl.cpp", 
    line=173) at /usr/include/boost/throw_exception.hpp:86
No locals.
#9  0x0806cb6f in ndn::util::NetworkMonitor::Impl::onReceiveRtnl (
    this=0x80c1e78, error=..., nBytesReceived=0)
    at ../src/util/detail/network-monitor-impl-rtnl.cpp:173
        __func__ = "onReceiveRtnl"
        __PRETTY_FUNCTION__ = "void ndn::util::NetworkMonitor::Impl::onReceiveRt---Type <return> to continue, or q <return> to quit---
nl(const boost::system::error_code&, size_t)"
        nlh = <optimized out>
#10 0x08072577 in std::_Mem_fn_base<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int), true>::operator()<boost::system::error_code const&, unsigned int const&, void> (__object=<optimized out>, 
    this=0xbffff4e4) at /usr/include/c++/5/functional:600
No locals.
#11 std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Placeholder<2>)>::__call<void, boost::system::error_code const&, unsigned int const&, 0u, 1u, 2u>(std::tuple<boost::system::error_code const&, unsigned int const&>&&, std::_Index_tuple<0u, 1u, 2u>) (
    __args=<unknown type in /home/ubuntu/x, CU 0x2c49d, DIE 0x89fd0>, 
    this=0xbffff4e4) at /usr/include/c++/5/functional:1074
No locals.
#12 std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Placeholder<2>)>::operator()<boost::system::error_code const&, unsigned int const&, void>(boost::system::error_code const&, unsigned int const&) (this=0xbffff4e4) at /usr/include/c++/5/functional:1133
No locals.
#13 boost::asio::detail::binder2<std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::---Type <return> to continue, or q <return> to quit---
NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Placeholder<2>)>, boost::system::error_code, unsigned int>::operator()() (this=0xbffff4e4)
    at /usr/include/boost/asio/detail/bind_handler.hpp:127
No locals.
#14 boost::asio::asio_handler_invoke<boost::asio::detail::binder2<std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Placeholder<2>)>, boost::system::error_code, unsigned int> >(boost::asio::detail::binder2<std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Placeholder<2>)>, boost::system::error_code, unsigned int>&, ...) (function=...)
    at /usr/include/boost/asio/handler_invoke_hook.hpp:69
No locals.
#15 boost_asio_handler_invoke_helpers::invoke<boost::asio::detail::binder2<std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Placeholder<2>)>, boost::system::error_code, unsigned int>, std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Placeholder<2>)> >(boost::asio::detail::binder2<std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Pla---Type <return> to continue, or q <return> to quit---
ceholder<2>)>, boost::system::error_code, unsigned int>&, std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Placeholder<2>)>&) (context=..., function=...)
    at /usr/include/boost/asio/detail/handler_invoke_helpers.hpp:37
No locals.
#16 boost::asio::detail::descriptor_read_op<boost::asio::mutable_buffers_1, std::_Bind<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> (ndn::util::NetworkMonitor::Impl*, std::_Placeholder<1>, std::_Placeholder<2>)> >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned int) (owner=0x80c1d70, base=0x80c6af8)
    at /usr/include/boost/asio/detail/descriptor_read_op.hpp:104
        o = <optimized out>
        p = {h = 0xbffff4e4, v = 0x0, p = 0x0}
        handler = {
          handler_ = {<std::_Weak_result_type<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> >> = {<std::_Weak_result_type_impl<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)> >> = {<std::_Maybe_get_result_type<std::_Mem_fn<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int)>, void>> = {<No data fields>}, <No data fields>}, <No data fields>}, 
---Type <return> to continue, or q <return> to quit---
            _M_f = {<std::_Mem_fn_base<void (ndn::util::NetworkMonitor::Impl::*)(boost::system::error_code const&, unsigned int), true>> = {<std::_Maybe_unary_or_binary_function<void, ndn::util::NetworkMonitor::Impl*, boost::system::error_code const&, unsigned int>> = {<No data fields>}, 
                _M_pmf = (void (ndn::util::NetworkMonitor::Impl::*)(ndn::util::NetworkMonitor::Impl * const, const boost::system::error_code &, 
    unsigned int)) 0x806c36e <ndn::util::NetworkMonitor::Impl::onReceiveRtnl(boost::system::error_code const&, unsigned int)>}, <No data fields>}, 
            _M_bound_args = std::tuple containing = {[1] = 0x80c1e78, 
              [2] = {<std::_Placeholder<1>> = {<No data fields>}, <No data fields>}, [3] = {<std::_Placeholder<2>> = {<No data fields>}, <No data fields>}}}, 
          arg1_ = {m_val = 9, m_cat = 0xb7fcb064}, arg2_ = 0}
#17 0x08061018 in boost::asio::detail::task_io_service_operation::complete(boost::asio::detail::task_io_service&, boost::system::error_code const&, unsigned int) ()
No symbol table info available.
#18 0x08061eef in boost::asio::detail::task_io_service::do_run_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service_thread_info&, boost::system::error_code const&) ()
No symbol table info available.
#19 0x08061b1e in boost::asio::detail::task_io_service::run(boost::system::error_code&) ()
No symbol table info available.
---Type <return> to continue, or q <return> to quit---
#20 0x0806214d in boost::asio::io_service::run() ()
No symbol table info available.
#21 0x0805f2db in main ()
No symbol table info available.
Actions #29

Updated by Junxiao Shi about 7 years ago

Actions #30

Updated by Davide Pesavento about 7 years ago

Junxiao Shi wrote:

On Ubuntu 16.04 32-bit, http://gerrit.named-data.net/2708 patchset29 crashes if NetworkMonitor is destructed before onEnumerationCompleted is invoked.

The crash is somewhat expected since an exception is being thrown from a destructor, which causes std::terminate to be invoked. The real question is: why are you getting "bad file descriptor" at that point in the code?

Actions #31

Updated by Junxiao Shi about 7 years ago

Actions #32

Updated by Davide Pesavento about 7 years ago

We already encountered this problem in NFD (#1856).

When an Asio socket is destructed (or .close() is called), pending handlers are invoked with no error (instead of boost::asio::error::operation_aborted as documented). Therefore the handlers proceeds as if nothing bad happened and schedules another async read from the socket. However at that point the socket is closed, so the read results in a "bad file descriptor" error as above.

Patch set 30 solves this.

Actions #33

Updated by Davide Pesavento almost 7 years ago

  • Status changed from Code review to Closed
  • % Done changed from 90 to 100
  • Estimated time deleted (6.00 h)

Finally.

Actions

Also available in: Atom PDF