Linux is using DMA and hardware interrupts when you use epoll. Even though the function has a name that makes it look like it would do “polling” where polling means “actively ask the network card over and over again in a loop if it has any data yet” that isn’t what it actually does. The problem here is that “poll” can either mean that constant active checking or it can mean calling any of the related system calls in Linux, poll, select, or epoll. The system calls are just a way of asking the kernel to put your process to sleep so it stops consuming CPU and wake your process back up once data is available so there is something for your program to actually do. It turns out the kernel will go and do that efficiently for you using hardware interrupts and DMA. So if somebody tells you their code is polling you can’t really know if it’s active tight loop checking or hardware interrupt-based without further clarification.
The kernel will put your process to sleep and record what it was your process said it needed data for in order to wake up. Then when it gets a hardware interrupt from one of those data sources it will check the list of processes that were waiting to be woken up based on the availability of data from that source, and wake them up. It won’t endlessly ask the hardware if it has data in a tight loop.
Ironically if you go high performance enough, things come back around the other way again. Having your process actually go to sleep and have the kernel wake it up has some overhead, so some network card vendors have proprietary kernel modules that make it so that your process can directly actively poll on a bit in memory that indicates whether the card has data, and the card flips it. Then your process can react without the program counter jumping into the interrupt handler and the kernel having to look up your process and notify you. But this means your process never goes to sleep, so you burn more power. So it’s less efficient in power use but more efficient in latency.