вот её код
Код:
Код: Выделить всё
static void net_rx_action(struct softirq_action *h)
{
struct list_head *list = &__get_cpu_var(softnet_data).poll_list;
unsigned long time_limit = jiffies + 2;
int budget = netdev_budget;
void *have;
local_irq_disable();
while (!list_empty(list)) {
struct napi_struct *n;
int work, weight;
/* If softirq window is exhuasted then punt.
* Allow this to run for 2 jiffies since which will allow
* an average latency of 1.5/HZ.
*/
if (unlikely(budget <= 0 || time_after(jiffies, time_limit)))
goto softnet_break;
local_irq_enable();
/* Even though interrupts have been re-enabled, this
* access is safe because interrupts can only add new
* entries to the tail of this list, and only ->poll()
* calls can remove this head entry from the list.
*/
n = list_entry(list->next, struct napi_struct, poll_list);
have = netpoll_poll_lock(n);
weight = n->weight;
/* This NAPI_STATE_SCHED test is for avoiding a race
* with netpoll's poll_napi(). Only the entity which
* obtains the lock and sees NAPI_STATE_SCHED set will
* actually make the ->poll() call. Therefore we avoid
* accidently calling ->poll() when NAPI is not scheduled.
*/
work = 0;
if (test_bit(NAPI_STATE_SCHED, &n->state)) {
work = n->poll(n, weight);
trace_napi_poll(n);
}
WARN_ON_ONCE(work > weight);
budget -= work;
local_irq_disable();
/* Drivers must not modify the NAPI state if they
* consume the entire weight. In such cases this code
* still "owns" the NAPI instance and therefore can
* move the instance around on the list at-will.
*/
if (unlikely(work == weight)) {
if (unlikely(napi_disable_pending(n))) {
local_irq_enable();
napi_complete(n);
local_irq_disable();
} else
list_move_tail(&n->poll_list, list);
}
netpoll_poll_unlock(have);
}
out:
local_irq_enable();
#ifdef CONFIG_NET_DMA
/*
* There may not be any more sk_buffs coming right now, so push
* any pending DMA copies to hardware
*/
dma_issue_pending_all();
#endif
return;
softnet_break:
__get_cpu_var(netdev_rx_stat).time_squeeze++;
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
goto out;
}
Меня интересует этот участок
struct napi_struct *n;
n = list_entry(list->next, struct napi_struct, poll_list);
( если кто-то не помнит, вот описание функции list_entry )
list_entry(p, t, m) Возвращает адрес структуры типа t, включающей в себя поле типа list_head с именем m и адресом p
Как видно, код возвращает указатель на struct napi_struct ( определена в include/linux/netdevice.h)
Код:
Код: Выделить всё
struct napi_struct {
/* The poll_list must only be managed by the entity which
* changes the state of the NAPI_STATE_SCHED bit. This means
* whoever atomically sets that bit can add this napi_struct
* to the per-cpu poll_list, and whoever clears that bit
* can remove from the list right before clearing the bit.
*/
struct list_head poll_list;
unsigned long state;
int weight;
int (*poll)(struct napi_struct *, int);
#ifdef CONFIG_NETPOLL
spinlock_t poll_lock;
int poll_owner;
#endif
unsigned int gro_count;
struct net_device *dev;
struct list_head dev_list;
struct sk_buff *gro_list; // ЧТО ЭТО ЗА УКАЗАТЕЛЬ??????
struct sk_buff *skb;
};
Теперь поясню, что за функция такая net_rx_action - это процедура обработки NET_RX_SOFTIRQ по окончанию её работы, пакет skb должен передаться для обработки дальше, сетевому уровню сетевого стека. Она должна принимать из входной очереди текущего процессора пакеты и передавать их обрабатывающему протоколу.
Как я понял n->skb должен указывать на обрабатываемый пакет. Но при проверке после n = list_entry(list->next, struct napi_struct, poll_list);
оказывается что if( !n->skb ) printk ("Указатель на буфер сокета пуст!!! \n");
Мне не ясно! когда struct napi_struct будет содержать адрес текущего пакета,а также не понятно, как именно net_rx_action передаёт пакет вышележащим протоколам.
Рассчитываю на помощь.