This article original for freas_1990, reprint please indicate source: http://blog.csdn.net/freas_1990/article/details/42033025
Network cards and disks are the most demanding 2 peripherals in a modern server, let's look at how the Linux kernel handles high-performance NICs.
int Netif_rx (struct sk_buff *skb) {int this_cpu = smp_processor_id (); struct Softnet_data *queue;unsigned long flags;if (SK B->stamp.tv_sec = = 0) do_gettimeofday (&skb->stamp);/* The code is rearranged so the the When the CPU is congested, it is still operating. */queue = &softnet_data[this_cpu];local_irq_save (flags); Netdev_rx_stat[this_cpu].total++;if (queue->input_ Pkt_queue.qlen <= Netdev_max_backlog) {if (Queue->input_pkt_queue.qlen) {if (queue->throttle) goto drop; Enqueue:dev_hold (Skb->dev); __skb_queue_tail (&QUEUE->INPUT_PKT_QUEUE,SKB);/* Runs from IRQs or BH ' s, no need To Wake BH */cpu_raise_softirq (THIS_CPU, NET_RX_SOFTIRQ); Local_irq_restore (flags); #ifndef Offline_sampleget_sample_ Stats (THIS_CPU); #endifreturn Softnet_data[this_cpu].cng_level;} if (queue->throttle) {queue->throttle = 0; #ifdef config_net_hw_flowcontrolif (Atomic_dec_and_test (&netdev_ dropping) netdev_wakeup (); #endif}goto Enqueue;} if (Queue->throttle = = 0) {queue->throttle = 1;netdev_rx_stat[this_cpu].throttled++; #ifdef config_net_hw_flowcontrolatomic_inc (& netdev_dropping); #endif}drop:netdev_rx_stat[this_cpu].dropped++;local_irq_restore (Flags); KFREE_SKB (SKB); return Net_rx_drop;} /* Deliver SKB to a old protocol, which are not threaded well or which does not understand shared skbs. */static int deliver_to_old_ones (struct packet_type *pt, struct sk_buff *skb, int last) {static spinlock_t Net_bh_lock = SP in_lock_unlocked;int ret = net_rx_drop;if (!last) {SKB = Skb_clone (SKB, gfp_atomic); if (SKB = = NULL) return ret;} if (Skb_is_nonlinear (SKB) && skb_linearize (SKB, gfp_atomic)! = 0) {KFREE_SKB (SKB); return ret;} /* The assumption (correct one) is this old protocols do not depened on BHs different of NET_BH and TIMER_BH. *//* emulate NET_BH with special spinlock */spin_lock (&net_bh_lock);/* Disable timers and wait for all timers Completi On */tasklet_disable (BH_TASK_VEC+TIMER_BH); ret = Pt->func (SKB, Skb->dev, PT); TASKLEt_hi_enable (BH_TASK_VEC+TIMER_BH); Spin_unlock (&net_bh_lock); return ret;}
static void Net_rx_action (struct softirq_action *h) {int this_cpu = smp_processor_id (); struct Softnet_data *queue = &s oftnet_data[this_cpu];unsigned long start_time = Jiffies;int Bugdet = Netdev_max_backlog;br_read_lock (BR_NETPROTO_ LOCK); for (;;) {struct Sk_buff *skb;struct net_device *rx_dev;local_irq_disable (); SKB = __skb_dequeue (&queue->input_pkt_ Queue), local_irq_enable (), if (SKB = = NULL) Break;skb_bond (SKB), Rx_dev = skb->dev; #ifdef Config_net_fastrouteif ( Skb->pkt_type = = Packet_fastroute) {netdev_rx_stat[this_cpu].fastroute_deferred_out++;d ev_queue_xmit (SKB);d ev_ Put (rx_dev); continue;} #endifskb->h.raw = Skb->nh.raw = skb->data; {struct Packet_type *ptype, *pt_prev;unsigned short type = Skb->protocol;pt_prev = null;for (ptype = Ptype_all; ptype; PType = Ptype->next) {if (!ptype->dev | | ptype->dev = = skb->dev) {if (Pt_prev) {if (!pt_prev->data) {delive R_to_old_ones (Pt_prev, SKB, 0);} else {atomic_inc (&skb->users);p T_prev->func (SKB, Skb->dev, Pt_prev);}} Pt_prev = PType;}} #ifdef config_net_divertif (Skb->dev->divert && skb->dev->divert->divert) Handle_diverter ( SKB); #endif/* Config_net_divert */#if defined (Config_bridge) | | Defined (config_bridge_module) if (skb->dev->br_port! = NULL && Br_handle_frame_hook! = null) {Handle_brid GE (SKB, pt_prev);d ev_put (Rx_dev); continue;} #endiffor (Ptype=ptype_base[ntohs (type) &15];p type;ptype=ptype->next) {if (Ptype->type = = Type && (! Ptype->dev | | Ptype->dev = = Skb->dev) {if (Pt_prev) {if (!pt_prev->data) deliver_to_old_ones (Pt_prev, SKB, 0); else {Atomic_ Inc (&skb->users);p t_prev->func (SKB, Skb->dev, Pt_prev);}} Pt_prev = PType;}} if (Pt_prev) {if (!pt_prev->data) deliver_to_old_ones (Pt_prev, SKB, 1); Elsept_prev->func (SKB, Skb->dev, Pt_ prev);} ELSEKFREE_SKB (SKB);} Dev_put (Rx_dev); if (bugdet--< 0 | | jiffies-start_time > 1) goto softnet_break; #ifdef CONFIG_NET_HW_FLOWCOntrolif (queue->throttle && Queue->input_pkt_queue.qlen < No_cong_thresh) {if (Atomic_dec_and_test ( &netdev_dropping) {queue->throttle = 0;netdev_wakeup (); goto Softnet_break;}} #endif}br_read_unlock (Br_netproto_lock); local_irq_disable (); if (queue->throttle) {queue->throttle = 0; #ifdef Config_net_hw_flowcontrolif (Atomic_dec_and_test (&netdev_dropping)) netdev_wakeup (); #endif}local_irq_enable ( ); Net_profile_leave (softnet_process); Return;softnet_break:br_read_unlock (Br_netproto_lock); Local_irq_disable () ; netdev_rx_stat[this_cpu].time_squeeze++;/* this already runs in BH context, no need to wake up BH ' s */CPU_RAISE_SOFTIRQ (t HIS_CPU, NET_RX_SOFTIRQ); local_irq_enable (); Net_profile_leave (softnet_process); return;}
Do you understand me?
Paralyzed, the Linux kernel in the network card asynchronous processing mechanism than the traditional BSD more aggressive, performance is much better, but the stability also decreases!
The essence of the Linux kernel collection