Hi,
akasei wrote:I wonder how it works (or should) the TCP/IP stack in the operating system.
Is each layer (ethernet [sending] / ip / tcp / icmp / arp ... and so on) a separate process / thread
That depends on the OS. For a true micro-kernel you'd want processes in user-space, but you might not follow the "7 layer OSI model" (e.g. it might be one process per network card driver plus one process for everything else). For a monolithic kernel it depends on what the kernel provides - e.g. kernel threads, some kind of light-weight alternative like deferred procedure calls (Windows) or tasklettes (Linux), "nothing", etc.
Also note that
sometimes you want to join two or more network devices together to create a virtual network device (sort of like how you might join 2 or more storage devices with a RAID layer to get a virtual storage device); and sometimes a network device is not used for TCP/IP at all (e.g. assigned to a virtual machine, using a different protocol stack like IPX); and sometimes you want two or more separate TCP/IP stacks (e.g. gateway/firewall with one TCP/IP stack for the public side and separate TCP/IP stack for the "internal LAN" side, with special forwarding between the TCP/IP stacks, like maybe a set of NAT rules).
For flexibility you'd want a modular design, possibly where network drivers provide a simple (and standardised) low level "send/receive packet" interface so it's easy to "mix and match" middle layers and upper layers. However, for performance you probably don't want that (e.g. a simple "send/receive packet" interface can be too simple to allow "offload engines" in high speed NICs to be used), so you end up with a complicated mess as you try to make compromises between flexibility/modularity and performance.
akasei wrote:For example, the Ethernet layer (incoming packets) is already managed by the interrupt generated from the network card.
You should think of a device driver as "glue between two interfaces", where one of the interfaces is "software side" (e.g. how the driver talks to the kernel or processes) and you are responsible for designing the "software side interface" for your OS, and one of the interfaces is "hardware side" (how the driver talks to the device itself) where typically you have no control over the design at all (it's designed by the hardware manufacturer). For the glue in the middle, the device driver developer needs to be free to do whatever makes sense for their specific device, and (unless you're writing a driver) you have no reason to make assumptions about what might or might not make sense.
For examples; for some cases (10 GiB+ ethernet cards) under heavy load an IRQ handler can struggle to keep up so (to avoid the overhead of IRQs) you end up switching to polling without using IRQs; for some cases (loopback device) there isn't any device involved; for some cases the device driver ends up being a "no hardware access" child that communicates with a parent device driver (e.g. USB ethernet adapter driver that talks to a USB controller driver); and for some cases a device can be using more than one IRQ (e.g. a group of 16 IRQs and/or one IRQ per CPU).
Cheers,
Brendan