Skip to content

Commit

Permalink
Kernel: Introduce the NetworkingManagement singleton
Browse files Browse the repository at this point in the history
Instead of initializing network adapters in init.cpp, let's move that
logic into a separate class to handle this.
Also, it seems like a good idea to shift responsiblity on enumeration
of network adapters after the boot process, so this singleton will take
care of finding the appropriate network adapter when asked to with an
IPv4 address or interface name.

With this change being merged, we simplify the creation logic of
NetworkAdapter derived classes, so we enumerate the PCI bus only once,
searching for driver candidates when doing so, and we let each driver
to test if it is resposible for the specified PCI device.
  • Loading branch information
supercomputer7 authored and alimpfard committed Jun 9, 2021
1 parent 8b1d4d1 commit 1c94b5e
Show file tree
Hide file tree
Showing 20 changed files with 211 additions and 116 deletions.
1 change: 1 addition & 0 deletions Kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ set(KERNEL_SOURCES
Net/LoopbackAdapter.cpp
Net/NE2000NetworkAdapter.cpp
Net/NetworkAdapter.cpp
Net/NetworkingManagement.cpp
Net/NetworkTask.cpp
Net/RTL8139NetworkAdapter.cpp
Net/Routing.cpp
Expand Down
3 changes: 2 additions & 1 deletion Kernel/FileSystem/ProcFS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <Kernel/Module.h>
#include <Kernel/Net/LocalSocket.h>
#include <Kernel/Net/NetworkAdapter.h>
#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Net/Routing.h>
#include <Kernel/Net/TCPSocket.h>
#include <Kernel/Net/UDPSocket.h>
Expand Down Expand Up @@ -477,7 +478,7 @@ static bool procfs$pid_perf_events(InodeIdentifier identifier, KBufferBuilder& b
static bool procfs$net_adapters(InodeIdentifier, KBufferBuilder& builder)
{
JsonArraySerializer array { builder };
NetworkAdapter::for_each([&array](auto& adapter) {
NetworkingManagement::the().for_each([&array](auto& adapter) {
auto obj = array.add_object();
obj.add("name", adapter.name());
obj.add("class_name", adapter.class_name());
Expand Down
19 changes: 8 additions & 11 deletions Kernel/Net/E1000NetworkAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,18 +156,15 @@ UNMAP_AFTER_INIT static bool is_valid_device_id(u16 device_id)
}
}

UNMAP_AFTER_INIT void E1000NetworkAdapter::detect()
UNMAP_AFTER_INIT RefPtr<E1000NetworkAdapter> E1000NetworkAdapter::try_to_initialize(PCI::Address address)
{
PCI::enumerate([&](const PCI::Address& address, PCI::ID id) {
if (address.is_null())
return;
if (id.vendor_id != (u16)PCIVendorID::Intel)
return;
if (!is_valid_device_id(id.device_id))
return;
u8 irq = PCI::get_interrupt_line(address);
[[maybe_unused]] auto& unused = adopt_ref(*new E1000NetworkAdapter(address, irq)).leak_ref();
});
auto id = PCI::get_id(address);
if (id.vendor_id != (u16)PCIVendorID::Intel)
return {};
if (!is_valid_device_id(id.device_id))
return {};
u8 irq = PCI::get_interrupt_line(address);
return adopt_ref_if_nonnull(new E1000NetworkAdapter(address, irq));
}

UNMAP_AFTER_INIT E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address address, u8 irq)
Expand Down
4 changes: 2 additions & 2 deletions Kernel/Net/E1000NetworkAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ namespace Kernel {
class E1000NetworkAdapter final : public NetworkAdapter
, public PCI::Device {
public:
static void detect();
static RefPtr<E1000NetworkAdapter> try_to_initialize(PCI::Address);

E1000NetworkAdapter(PCI::Address, u8 irq);
virtual ~E1000NetworkAdapter() override;

virtual void send_raw(ReadonlyBytes) override;
Expand All @@ -31,6 +30,7 @@ class E1000NetworkAdapter final : public NetworkAdapter
virtual const char* purpose() const override { return class_name(); }

private:
E1000NetworkAdapter(PCI::Address, u8 irq);
virtual void handle_irq(const RegisterState&) override;
virtual const char* class_name() const override { return "E1000NetworkAdapter"; }

Expand Down
5 changes: 3 additions & 2 deletions Kernel/Net/IPv4Socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <Kernel/Net/IPv4.h>
#include <Kernel/Net/IPv4Socket.h>
#include <Kernel/Net/NetworkAdapter.h>
#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Net/Routing.h>
#include <Kernel/Net/TCP.h>
#include <Kernel/Net/TCPSocket.h>
Expand Down Expand Up @@ -582,7 +583,7 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
if (copied_ifname.is_null())
return -EFAULT;

auto adapter = NetworkAdapter::lookup_by_name(copied_ifname);
auto adapter = NetworkingManagement::the().lookup_by_name(copied_ifname);
if (!adapter)
return -ENODEV;

Expand Down Expand Up @@ -615,7 +616,7 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
memcpy(namebuf, ifr.ifr_name, IFNAMSIZ);
namebuf[sizeof(namebuf) - 1] = '\0';

auto adapter = NetworkAdapter::lookup_by_name(namebuf);
auto adapter = NetworkingManagement::the().lookup_by_name(namebuf);
if (!adapter)
return -ENODEV;

Expand Down
8 changes: 5 additions & 3 deletions Kernel/Net/LoopbackAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@

namespace Kernel {

static AK::Singleton<LoopbackAdapter> s_loopback;
static bool s_loopback_initialized = false;

LoopbackAdapter& LoopbackAdapter::the()
NonnullRefPtr<LoopbackAdapter> LoopbackAdapter::create()
{
return *s_loopback;
return adopt_ref(*new LoopbackAdapter());
}

LoopbackAdapter::LoopbackAdapter()
{
VERIFY(!s_loopback_initialized);
s_loopback_initialized = true;
set_loopback_name();
set_mtu(65536);
set_mac_address({ 19, 85, 2, 9, 0x55, 0xaa });
Expand Down
6 changes: 4 additions & 2 deletions Kernel/Net/LoopbackAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ namespace Kernel {

class LoopbackAdapter final : public NetworkAdapter {
AK_MAKE_ETERNAL
public:

private:
LoopbackAdapter();
static LoopbackAdapter& the();

public:
static NonnullRefPtr<LoopbackAdapter> create();
virtual ~LoopbackAdapter() override;

virtual void send_raw(ReadonlyBytes) override;
Expand Down
15 changes: 6 additions & 9 deletions Kernel/Net/NE2000NetworkAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ struct [[gnu::packed]] received_packet_header {
u16 length;
};

UNMAP_AFTER_INIT void NE2000NetworkAdapter::detect()
UNMAP_AFTER_INIT RefPtr<NE2000NetworkAdapter> NE2000NetworkAdapter::try_to_initialize(PCI::Address address)
{
constexpr auto ne2k_ids = Array {
PCI::ID { 0x10EC, 0x8029 }, // RealTek RTL-8029(AS)
Expand All @@ -152,14 +152,11 @@ UNMAP_AFTER_INIT void NE2000NetworkAdapter::detect()
PCI::ID { 0x12c3, 0x5598 }, // Holtek HT80229
PCI::ID { 0x8c4a, 0x1980 }, // Winbond W89C940 (misprogrammed)
};
PCI::enumerate([&](const PCI::Address& address, PCI::ID id) {
if (address.is_null())
return;
if (!ne2k_ids.span().contains_slow(id))
return;
u8 irq = PCI::get_interrupt_line(address);
[[maybe_unused]] auto& unused = adopt_ref(*new NE2000NetworkAdapter(address, irq)).leak_ref();
});
auto id = PCI::get_id(address);
if (!ne2k_ids.span().contains_slow(id))
return {};
u8 irq = PCI::get_interrupt_line(address);
return adopt_ref_if_nonnull(new NE2000NetworkAdapter(address, irq));
}

UNMAP_AFTER_INIT NE2000NetworkAdapter::NE2000NetworkAdapter(PCI::Address address, u8 irq)
Expand Down
4 changes: 2 additions & 2 deletions Kernel/Net/NE2000NetworkAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ namespace Kernel {
class NE2000NetworkAdapter final : public NetworkAdapter
, public PCI::Device {
public:
static void detect();
static RefPtr<NE2000NetworkAdapter> try_to_initialize(PCI::Address);

NE2000NetworkAdapter(PCI::Address, u8 irq);
virtual ~NE2000NetworkAdapter() override;

virtual void send_raw(ReadonlyBytes) override;
Expand All @@ -29,6 +28,7 @@ class NE2000NetworkAdapter final : public NetworkAdapter
virtual const char* purpose() const override { return class_name(); }

private:
NE2000NetworkAdapter(PCI::Address, u8 irq);
virtual void handle_irq(const RegisterState&) override;
virtual const char* class_name() const override { return "NE2000NetworkAdapter"; }

Expand Down
40 changes: 3 additions & 37 deletions Kernel/Net/NetworkAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,19 @@
#include <Kernel/Net/EtherType.h>
#include <Kernel/Net/LoopbackAdapter.h>
#include <Kernel/Net/NetworkAdapter.h>
#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Process.h>
#include <Kernel/Random.h>
#include <Kernel/StdLib.h>

namespace Kernel {

static AK::Singleton<Lockable<HashTable<NetworkAdapter*>>> s_table;

Lockable<HashTable<NetworkAdapter*>>& NetworkAdapter::all_adapters()
{
return *s_table;
}

RefPtr<NetworkAdapter> NetworkAdapter::from_ipv4_address(const IPv4Address& address)
{
Locker locker(all_adapters().lock());
for (auto* adapter : all_adapters().resource()) {
if (adapter->ipv4_address() == address || adapter->ipv4_broadcast() == address)
return adapter;
}
if (address[0] == 0 && address[1] == 0 && address[2] == 0 && address[3] == 0)
return LoopbackAdapter::the();
if (address[0] == 127)
return LoopbackAdapter::the();
return nullptr;
}

RefPtr<NetworkAdapter> NetworkAdapter::lookup_by_name(const StringView& name)
{
NetworkAdapter* found_adapter = nullptr;
for_each([&](auto& adapter) {
if (adapter.name() == name)
found_adapter = &adapter;
});
return found_adapter;
}

NetworkAdapter::NetworkAdapter()
{
// FIXME: I wanna lock :(
all_adapters().resource().set(this);
}

NetworkAdapter::~NetworkAdapter()
{
// FIXME: I wanna lock :(
all_adapters().resource().remove(this);
}

void NetworkAdapter::send_packet(ReadonlyBytes packet)
Expand Down Expand Up @@ -199,14 +165,14 @@ void NetworkAdapter::set_interface_name(const PCI::Address& pci_address)
{
// Note: This stands for e - "Ethernet", p - "Port" as for PCI bus, "s" for slot as for PCI slot
auto name = String::formatted("ep{}s{}", pci_address.bus(), pci_address.device());
VERIFY(!lookup_by_name(name));
VERIFY(!NetworkingManagement::the().lookup_by_name(name));
m_name = move(name);
}

void NetworkAdapter::set_loopback_name()
{
auto name = String("loop");
VERIFY(!lookup_by_name(name));
VERIFY(!NetworkingManagement::the().lookup_by_name(name));
m_name = move(name);
}
}
12 changes: 0 additions & 12 deletions Kernel/Net/NetworkAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,6 @@ struct PacketWithTimestamp : public RefCounted<PacketWithTimestamp> {
class NetworkAdapter : public RefCounted<NetworkAdapter>
, public Weakable<NetworkAdapter> {
public:
template<typename Callback>
static inline void for_each(Callback callback)
{
Locker locker(all_adapters().lock());
for (auto& it : all_adapters().resource())
callback(*it);
}

static RefPtr<NetworkAdapter> from_ipv4_address(const IPv4Address&);
static RefPtr<NetworkAdapter> lookup_by_name(const StringView&);
virtual ~NetworkAdapter();

virtual const char* class_name() const = 0;
Expand Down Expand Up @@ -103,8 +93,6 @@ class NetworkAdapter : public RefCounted<NetworkAdapter>
void set_loopback_name();

private:
static Lockable<HashTable<NetworkAdapter*>>& all_adapters();

MACAddress m_mac_address;
IPv4Address m_ipv4_address;
IPv4Address m_ipv4_netmask;
Expand Down
15 changes: 8 additions & 7 deletions Kernel/Net/NetworkTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <Kernel/Net/IPv4Socket.h>
#include <Kernel/Net/LoopbackAdapter.h>
#include <Kernel/Net/NetworkTask.h>
#include <Kernel/Net/NetworkingManagement.h>
#include <Kernel/Net/Routing.h>
#include <Kernel/Net/TCP.h>
#include <Kernel/Net/TCPSocket.h>
Expand Down Expand Up @@ -55,7 +56,7 @@ void NetworkTask_main(void*)

WaitQueue packet_wait_queue;
int pending_packets = 0;
NetworkAdapter::for_each([&](auto& adapter) {
NetworkingManagement::the().for_each([&](auto& adapter) {
dmesgln("NetworkTask: {} network adapter found: hw={}", adapter.class_name(), adapter.mac_address().to_string());

if (String(adapter.class_name()) == "LoopbackAdapter") {
Expand All @@ -74,7 +75,7 @@ void NetworkTask_main(void*)
if (pending_packets == 0)
return 0;
size_t packet_size = 0;
NetworkAdapter::for_each([&](auto& adapter) {
NetworkingManagement::the().for_each([&](auto& adapter) {
if (packet_size || !adapter.has_queued_packets())
return;
packet_size = adapter.dequeue_packet(buffer, buffer_size, packet_timestamp);
Expand Down Expand Up @@ -155,7 +156,7 @@ void handle_arp(const EthernetFrameHeader& eth, size_t frame_size)

if (packet.operation() == ARPOperation::Request) {
// Who has this IP address?
if (auto adapter = NetworkAdapter::from_ipv4_address(packet.target_protocol_address())) {
if (auto adapter = NetworkingManagement::the().from_ipv4_address(packet.target_protocol_address())) {
// We do!
dbgln("handle_arp: Responding to ARP request for my IPv4 address ({})", adapter->ipv4_address());
ARPPacket response;
Expand Down Expand Up @@ -193,7 +194,7 @@ void handle_ipv4(const EthernetFrameHeader& eth, size_t frame_size, const Time&

dbgln_if(IPV4_DEBUG, "handle_ipv4: source={}, destination={}", packet.source(), packet.destination());

NetworkAdapter::for_each([&](auto& adapter) {
NetworkingManagement::the().for_each([&](auto& adapter) {
if (adapter.link_up()) {
auto my_net = adapter.ipv4_address().to_u32() & adapter.ipv4_netmask().to_u32();
auto their_net = packet.source().to_u32() & adapter.ipv4_netmask().to_u32();
Expand Down Expand Up @@ -234,7 +235,7 @@ void handle_icmp(const EthernetFrameHeader& eth, const IPv4Packet& ipv4_packet,
socket.did_receive(ipv4_packet.source(), 0, { &ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size() }, packet_timestamp);
}

auto adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination());
auto adapter = NetworkingManagement::the().from_ipv4_address(ipv4_packet.destination());
if (!adapter)
return;

Expand Down Expand Up @@ -292,7 +293,7 @@ void handle_udp(const IPv4Packet& ipv4_packet, const Time& packet_timestamp)

auto& destination = ipv4_packet.destination();

if (destination == IPv4Address(255, 255, 255, 255) || NetworkAdapter::from_ipv4_address(destination) || socket->multicast_memberships().contains_slow(destination))
if (destination == IPv4Address(255, 255, 255, 255) || NetworkingManagement::the().from_ipv4_address(destination) || socket->multicast_memberships().contains_slow(destination))
socket->did_receive(ipv4_packet.source(), udp_packet.source_port(), { &ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size() }, packet_timestamp);
}

Expand Down Expand Up @@ -365,7 +366,7 @@ void handle_tcp(const IPv4Packet& ipv4_packet, const Time& packet_timestamp)
tcp_packet.window_size(),
payload_size);

auto adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination());
auto adapter = NetworkingManagement::the().from_ipv4_address(ipv4_packet.destination());
if (!adapter) {
dbgln("handle_tcp: this packet is not for me, it's for {}", ipv4_packet.destination());
return;
Expand Down
Loading

0 comments on commit 1c94b5e

Please sign in to comment.