diff --git a/src/arch/x86_64/kernel/apic.rs b/src/arch/x86_64/kernel/apic.rs
index 89f8594cd57248fccf4f894a6fccb9fceae82942..8853d5dcf6747de0c35f74e9ee2ad363eaf4647b 100644
--- a/src/arch/x86_64/kernel/apic.rs
+++ b/src/arch/x86_64/kernel/apic.rs
@@ -634,6 +634,11 @@ pub fn init_local_apic() {
 	);
 }
 
+pub(crate) fn assign_irq_to_core(irq: u8, core_id: CoreId) {
+	info!("Assign interrupt {} to core {}", irq, core_id);
+	ioapic_inton(irq, core_id.try_into().unwrap()).unwrap();
+}
+
 fn calibrate_timer() {
 	// The APIC Timer is used to provide a one-shot interrupt for the tickless timer
 	// implemented through processor::get_timer_ticks.
diff --git a/src/drivers/net/mod.rs b/src/drivers/net/mod.rs
index 673e0b500ee458df60d42eea491d9e0e767ed13e..cb455bcfa4511b10e7e0b4dddf9af538317d512e 100644
--- a/src/drivers/net/mod.rs
+++ b/src/drivers/net/mod.rs
@@ -40,6 +40,8 @@ pub trait NetworkInterface {
 	fn set_polling_mode(&mut self, value: bool);
 	/// Handle interrupt and check if a packet is available
 	fn handle_interrupt(&mut self) -> bool;
+	/// handle interrupt on the same core, where the current task is running
+	fn assign_task_to_nic(&self);
 }
 
 #[cfg(all(not(feature = "newlib"), target_arch = "x86_64"))]
diff --git a/src/drivers/net/rtl8139.rs b/src/drivers/net/rtl8139.rs
index 0f52fc58fec8615342aa18d0606742389ec71dc7..87de243ba786ba4fd3ced7286c71105c3a3ba8d6 100644
--- a/src/drivers/net/rtl8139.rs
+++ b/src/drivers/net/rtl8139.rs
@@ -8,10 +8,11 @@ use core::mem;
 
 use crate::arch::kernel::irq::*;
 use crate::arch::kernel::pci;
-use crate::arch::kernel::percore::increment_irq_counter;
+use crate::arch::kernel::percore::{core_id, increment_irq_counter};
 use crate::arch::mm::paging::virt_to_phys;
 use crate::arch::mm::VirtAddr;
 use crate::drivers::error::DriverError;
+use crate::drivers::net::apic::assign_irq_to_core;
 use crate::drivers::net::{network_irqhandler, NetworkInterface};
 use crate::x86::io::*;
 
@@ -217,6 +218,10 @@ impl NetworkInterface for RTL8139Driver {
 		self.mac
 	}
 
+	fn assign_task_to_nic(&self) {
+		assign_irq_to_core(self.irq, core_id());
+	}
+
 	/// Returns the current MTU of the device.
 	fn get_mtu(&self) -> u16 {
 		self.mtu
diff --git a/src/drivers/net/virtio_net.rs b/src/drivers/net/virtio_net.rs
index f9b4afc6c4ad5a96e8e37249d763d8de9c842149..b4c649254e12950fc143f7e769de084aed0899bf 100644
--- a/src/drivers/net/virtio_net.rs
+++ b/src/drivers/net/virtio_net.rs
@@ -4,7 +4,7 @@
 
 #[cfg(not(feature = "newlib"))]
 use super::netwakeup;
-use crate::arch::kernel::percore::increment_irq_counter;
+use crate::arch::kernel::percore::{core_id, increment_irq_counter};
 use crate::config::VIRTIO_MAX_QUEUE_SIZE;
 use crate::drivers::net::NetworkInterface;
 
@@ -16,6 +16,7 @@ use core::mem;
 use core::result::Result;
 use core::{cell::RefCell, cmp::Ordering};
 
+use crate::drivers::net::apic::assign_irq_to_core;
 #[cfg(not(feature = "pci"))]
 use crate::drivers::net::virtio_mmio::NetDevCfgRaw;
 #[cfg(feature = "pci")]
@@ -515,6 +516,10 @@ impl NetworkInterface for VirtioNetDriver {
 		}
 	}
 
+	fn assign_task_to_nic(&self) {
+		assign_irq_to_core(self.irq, core_id());
+	}
+
 	/// Returns the current MTU of the device.
 	/// Currently, if VIRTIO_NET_F_MAC is not set
 	//  MTU is set static to 1500 bytes.
diff --git a/src/syscalls/interfaces/mod.rs b/src/syscalls/interfaces/mod.rs
index 5f9b66f4220bc93bc2aeb40213ca6a6e4151660b..676a51ff83cf15accdc92936b7a4dd71110f2576 100644
--- a/src/syscalls/interfaces/mod.rs
+++ b/src/syscalls/interfaces/mod.rs
@@ -127,6 +127,13 @@ pub trait SyscallInterface: Send + Sync {
 		Err(())
 	}
 
+	fn assign_task_to_nic(&self) {
+		#[cfg(not(target_arch = "aarch64"))]
+		if let Some(driver) = get_network_driver() {
+			driver.lock().assign_task_to_nic();
+		}
+	}
+
 	fn get_mtu(&self) -> Result<u16, ()> {
 		#[cfg(not(target_arch = "aarch64"))]
 		match get_network_driver() {
diff --git a/src/syscalls/mod.rs b/src/syscalls/mod.rs
index 037543640135e9865fc1b4ff6d4d6b87362e91ff..cc0ac4d52b5e187b279e5a9dca3f77fa2de07780 100644
--- a/src/syscalls/mod.rs
+++ b/src/syscalls/mod.rs
@@ -103,6 +103,17 @@ pub fn sys_get_mac_address() -> Result<[u8; 6], ()> {
 	kernel_function!(__sys_get_mac_address())
 }
 
+extern "C" fn __sys_assign_task_to_nic() {
+	unsafe {
+		SYS.assign_task_to_nic();
+	}
+}
+
+#[no_mangle]
+fn sys_assign_task_to_nic() {
+	kernel_function!(__sys_assign_task_to_nic());
+}
+
 #[allow(improper_ctypes_definitions)]
 extern "C" fn __sys_get_mtu() -> Result<u16, ()> {
 	unsafe { SYS.get_mtu() }