Interface Manager#
The InterfaceManager class provides centralized management of network interfaces in Join. It monitors system interfaces, handles creation and deletion, and notifies listeners of network changes through an event-driven architecture.
InterfaceManager is integrated with the Join reactor and automatically tracks interface and address changes via Linux Netlink.
Getting an instance#
InterfaceManager is a singleton. Use instance() for normal usage.
A custom Reactor* can be injected by constructing directly:
#include <join/interfacemanager.hpp>
using namespace join;
// Normal usage — singleton
InterfaceManager& manager = InterfaceManager::instance();
// Custom reactor
Reactor myReactor;
InterfaceManager manager(&myReactor);On construction the manager opens a Netlink socket, subscribes to link and address events, registers itself with the reactor, and performs an initial synchronous refresh().
InterfaceManager is neither copyable nor movable.
Finding interfaces#
Find by index#
Interface::Ptr eth0 = manager.findByIndex(2);
if (!eth0)
{
// interface not found
}Find by name#
Interface::Ptr eth0 = manager.findByName("eth0");
if (!eth0)
{
// interface not found
}Enumerate all interfaces#
for (const auto& iface : manager.enumerate())
{
std::cout << iface->name() << " (" << iface->index() << ")\n";
}Creating interfaces#
All creation methods default to asynchronous (sync = false).
Pass true to block until the kernel confirms the operation.
Dummy interface#
// Asynchronous (default)
manager.createDummyInterface("dummy0");
// Synchronous
if (manager.createDummyInterface("dummy0", true) == -1)
{
std::cerr << lastError.message() << "\n";
}Bridge interface#
manager.createBridgeInterface("br0", true);VLAN interface#
uint16_t vlanId = 100;
// By parent index
manager.createVlanInterface("eth0.100", 2, vlanId, ETH_P_8021Q, true);
// By parent name
manager.createVlanInterface("eth0.100", "eth0", vlanId, ETH_P_8021Q, true);⚠️ VLAN IDs must be in the range 1–4094. ID 0 is reserved and returns -1.
Virtual Ethernet pair (veth)#
// Both ends in current namespace
manager.createVethInterface("veth0", "veth1", nullptr, true);
// Peer moved to a different namespace
pid_t containerPid = 12345;
manager.createVethInterface("veth0", "veth1", &containerPid, true);GRE tunnel#
IpAddress local("192.168.1.1");
IpAddress remote("192.168.2.1");
uint32_t ikey = 1000;
uint32_t okey = 2000;
// By parent index, with keys
manager.createGreInterface("gre0", 2, local, remote, &ikey, &okey, 64, true);
// By parent name, without keys
manager.createGreInterface("gre0", "eth0", local, remote, nullptr, nullptr, 64, true);⚠️ localAddress and remoteAddress must be the same IP family (both IPv4 or both IPv6).
Deleting interfaces#
// By index
manager.removeInterface(10, true);
// By name
manager.removeInterface("dummy0", true);Refreshing interface data#
refresh() clears the cache and re-dumps link and address data from the kernel synchronously:
if (manager.refresh() == -1)
{
std::cerr << lastError.message() << "\n";
}Event notifications#
InterfaceChangeType flags#
enum class InterfaceChangeType : uint32_t
{
Added = 1 << 0, // interface did not exist before
Deleted = 1 << 1, // interface was removed
Modified = 1 << 2, // interface was updated
AdminStateChanged = 1 << 3, // IFF_UP changed
OperStateChanged = 1 << 4, // IFF_RUNNING changed
MacChanged = 1 << 5,
NameChanged = 1 << 6,
MtuChanged = 1 << 7,
KindChanged = 1 << 8,
MasterChanged = 1 << 9, // bridge membership changed
};Flags support all bitwise operators (&, |, ^, ~, &=, |=, ^=).
Link notifications#
addLinkListener returns a unique uint64_t id used to unregister later:
uint64_t id = manager.addLinkListener([](const LinkInfo& info) {
if (info.flags & InterfaceChangeType::Added)
{
std::cout << "Interface added: " << info.interface->name() << "\n";
}
if (info.flags & InterfaceChangeType::Deleted)
{
std::cout << "Interface deleted\n";
}
if (info.flags & InterfaceChangeType::AdminStateChanged)
{
std::cout << info.interface->name()
<< (info.interface->isEnabled() ? " up" : " down") << "\n";
}
});
// Unregister
manager.removeLinkListener(id);Address notifications#
uint64_t id = manager.addAddressListener([](const AddressInfo& info) {
if (info.flags & InterfaceChangeType::Added)
{
std::cout << "Address added: "
<< info.address.ip.toString()
<< "/" << info.address.prefix
<< " on " << info.interface->name() << "\n";
}
if (info.flags & InterfaceChangeType::Deleted)
{
std::cout << "Address removed: "
<< info.address.ip.toString()
<< "/" << info.address.prefix << "\n";
}
});
// Unregister
manager.removeAddressListener(id);Reactor integration#
InterfaceManager registers itself with the reactor on construction and unregisters on destruction. All listener callbacks are invoked from the reactor’s dispatcher thread — keep them short and non-blocking.
With a custom Reactor#
Reactor reactor;
InterfaceManager manager(&reactor);
ThreadPool pool;
pool.push([&reactor]() {
Thread::affinity(pthread_self(), 1);
Thread::priority(pthread_self(), 50);
reactor.run();
});
// ... application runs ...
reactor.stop();Information structures#
LinkInfo#
struct LinkInfo
{
Interface::Ptr interface; // the affected interface
InterfaceChangeType flags; // what changed (bitmask)
};AddressInfo#
struct AddressInfo : public LinkInfo
{
Interface::Address address; // address that was added or removed
// .ip — IpAddress
// .prefix — uint32_t
// .broadcast — IpAddress (IPv4)
};Error handling#
Methods return 0 on success, -1 on failure. Check join::lastError for details:
if (manager.createDummyInterface("dummy0", true) == -1)
{
std::cerr << "Failed: " << lastError.message() << "\n";
}Synchronous operations time out after 5 seconds and set Errc::TimedOut.
Best practices#
- Use synchronous mode when you need confirmation before proceeding.
- Use asynchronous mode for fire-and-forget batch operations.
- Register listeners before doing anything else to avoid missing early events.
- Keep callbacks short and non-blocking — they run on the reactor dispatcher thread.
- Store the returned id from
addLinkListener/addAddressListenerto be able to unregister. - Call
refresh()after external tools (e.g.ip,ifconfig) modify interfaces.
Summary#
| Feature | Supported |
|---|---|
| Interface enumeration | ✅ |
| Interface lookup | ✅ |
| Dummy interfaces | ✅ |
| Bridge interfaces | ✅ |
| VLAN interfaces | ✅ |
| Veth pairs | ✅ |
| GRE tunnels | ✅ |
| Interface deletion | ✅ |
| Link notifications | ✅ |
| Address notifications | ✅ |
| Reactor integration | ✅ |
| Custom Reactor | ✅ |
| Sync/async operations | ✅ |