📄 dev.c
字号:
if (pt_prev) { ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev); } else { kfree_skb(skb); /* Jamal, now you will not able to escape explaining * me how you were going to use this. :-) */ ret = NET_RX_DROP; }out: rcu_read_unlock(); return ret;}static int process_backlog(struct napi_struct *napi, int quota){ int work = 0; struct softnet_data *queue = &__get_cpu_var(softnet_data); unsigned long start_time = jiffies; napi->weight = weight_p; do { struct sk_buff *skb; struct net_device *dev; local_irq_disable(); skb = __skb_dequeue(&queue->input_pkt_queue); if (!skb) { __napi_complete(napi); local_irq_enable(); break; } local_irq_enable(); dev = skb->dev; netif_receive_skb(skb); dev_put(dev); } while (++work < quota && jiffies == start_time); return work;}/** * __napi_schedule - schedule for receive * @n: entry to schedule * * The entry's receive function will be scheduled to run */void fastcall __napi_schedule(struct napi_struct *n){ unsigned long flags; local_irq_save(flags); list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list); __raise_softirq_irqoff(NET_RX_SOFTIRQ); local_irq_restore(flags);}EXPORT_SYMBOL(__napi_schedule);static void net_rx_action(struct softirq_action *h){ struct list_head *list = &__get_cpu_var(softnet_data).poll_list; unsigned long start_time = jiffies; 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. * * Note that this is a slight policy change from the * previous NAPI code, which would allow up to 2 * jiffies to pass before breaking out. The test * used to be "jiffies - start_time > 1". */ if (unlikely(budget <= 0 || jiffies != start_time)) 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); 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))) __napi_complete(n); 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 */ if (!cpus_empty(net_dma.channel_mask)) { int chan_idx; for_each_cpu_mask(chan_idx, net_dma.channel_mask) { struct dma_chan *chan = net_dma.channels[chan_idx]; if (chan) dma_async_memcpy_issue_pending(chan); } }#endif return;softnet_break: __get_cpu_var(netdev_rx_stat).time_squeeze++; __raise_softirq_irqoff(NET_RX_SOFTIRQ); goto out;}static gifconf_func_t * gifconf_list [NPROTO];/** * register_gifconf - register a SIOCGIF handler * @family: Address family * @gifconf: Function handler * * Register protocol dependent address dumping routines. The handler * that is passed must not be freed or reused until it has been replaced * by another handler. */int register_gifconf(unsigned int family, gifconf_func_t * gifconf){ if (family >= NPROTO) return -EINVAL; gifconf_list[family] = gifconf; return 0;}/* * Map an interface index to its name (SIOCGIFNAME) *//* * We need this ioctl for efficient implementation of the * if_indextoname() function required by the IPv6 API. Without * it, we would have to search all the interfaces to find a * match. --pb */static int dev_ifname(struct net *net, struct ifreq __user *arg){ struct net_device *dev; struct ifreq ifr; /* * Fetch the caller's info block. */ if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) return -EFAULT; read_lock(&dev_base_lock); dev = __dev_get_by_index(net, ifr.ifr_ifindex); if (!dev) { read_unlock(&dev_base_lock); return -ENODEV; } strcpy(ifr.ifr_name, dev->name); read_unlock(&dev_base_lock); if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) return -EFAULT; return 0;}/* * Perform a SIOCGIFCONF call. This structure will change * size eventually, and there is nothing I can do about it. * Thus we will need a 'compatibility mode'. */static int dev_ifconf(struct net *net, char __user *arg){ struct ifconf ifc; struct net_device *dev; char __user *pos; int len; int total; int i; /* * Fetch the caller's info block. */ if (copy_from_user(&ifc, arg, sizeof(struct ifconf))) return -EFAULT; pos = ifc.ifc_buf; len = ifc.ifc_len; /* * Loop over the interfaces, and write an info block for each. */ total = 0; for_each_netdev(net, dev) { for (i = 0; i < NPROTO; i++) { if (gifconf_list[i]) { int done; if (!pos) done = gifconf_list[i](dev, NULL, 0); else done = gifconf_list[i](dev, pos + total, len - total); if (done < 0) return -EFAULT; total += done; } } } /* * All done. Write the updated control block back to the caller. */ ifc.ifc_len = total; /* * Both BSD and Solaris return 0 here, so we do too. */ return copy_to_user(arg, &ifc, sizeof(struct ifconf)) ? -EFAULT : 0;}#ifdef CONFIG_PROC_FS/* * This is invoked by the /proc filesystem handler to display a device * in detail. */void *dev_seq_start(struct seq_file *seq, loff_t *pos){ struct net *net = seq->private; loff_t off; struct net_device *dev; read_lock(&dev_base_lock); if (!*pos) return SEQ_START_TOKEN; off = 1; for_each_netdev(net, dev) if (off++ == *pos) return dev; return NULL;}void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct net *net = seq->private; ++*pos; return v == SEQ_START_TOKEN ? first_net_device(net) : next_net_device((struct net_device *)v);}void dev_seq_stop(struct seq_file *seq, void *v){ read_unlock(&dev_base_lock);}static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev){ struct net_device_stats *stats = dev->get_stats(dev); seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", dev->name, stats->rx_bytes, stats->rx_packets, stats->rx_errors, stats->rx_dropped + stats->rx_missed_errors, stats->rx_fifo_errors, stats->rx_length_errors + stats->rx_over_errors + stats->rx_crc_errors + stats->rx_frame_errors, stats->rx_compressed, stats->multicast, stats->tx_bytes, stats->tx_packets, stats->tx_errors, stats->tx_dropped, stats->tx_fifo_errors, stats->collisions, stats->tx_carrier_errors + stats->tx_aborted_errors + stats->tx_window_errors + stats->tx_heartbeat_errors, stats->tx_compressed);}/* * Called from the PROCfs module. This now uses the new arbitrary sized * /proc/net interface to create /proc/net/dev */static int dev_seq_show(struct seq_file *seq, void *v){ if (v == SEQ_START_TOKEN) seq_puts(seq, "Inter-| Receive " " | Transmit\n" " face |bytes packets errs drop fifo frame " "compressed multicast|bytes packets errs " "drop fifo colls carrier compressed\n"); else dev_seq_printf_stats(seq, v); return 0;}static struct netif_rx_stats *softnet_get_online(loff_t *pos){ struct netif_rx_stats *rc = NULL; while (*pos < NR_CPUS) if (cpu_online(*pos)) { rc = &per_cpu(netdev_rx_stat, *pos); break; } else ++*pos; return rc;}static void *softnet_seq_start(struct seq_file *seq, loff_t *pos){ return softnet_get_online(pos);}static void *softnet_seq_next(struct seq_file *seq, void *v, loff_t *pos){ ++*pos; return softnet_get_online(pos);}static void softnet_seq_stop(struct seq_file *seq, void *v){}static int softnet_seq_show(struct seq_file *seq, void *v){ struct netif_rx_stats *s = v; seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n", s->total, s->dropped, s->time_squeeze, 0, 0, 0, 0, 0, /* was fastroute */ s->cpu_collision ); return 0;}static const struct seq_operations dev_seq_ops = { .start = dev_seq_start, .next = dev_seq_next, .stop = dev_seq_stop, .show = dev_seq_show,};static int dev_seq_open(struct inode *inode, struct file *file){ struct seq_file *seq; int res; res = seq_open(file, &dev_seq_ops); if (!res) { seq = file->private_data; seq->private = get_proc_net(inode); if (!seq->private) { seq_release(inode, file); res = -ENXIO; } } return res;}static int dev_seq_release(struct inode *inode, struct file *file){ struct seq_file *seq = file->private_data; struct net *net = seq->private; put_net(net); return seq_release(inode, file);}static const struct file_operations dev_seq_fops = { .owner = THIS_MODULE, .open = dev_seq_open, .read = seq_read, .llseek = seq_lseek, .release = dev_seq_release,};static const struct seq_operations softnet_seq_ops = { .start = softnet_seq_start, .next = softnet_seq_next, .stop = softnet_seq_stop, .show = softnet_seq_show,};static int softnet_seq_open(struct inode *inode, struct file *file){ return seq_open(file, &softnet_seq_ops);}static const struct file_operations softnet_seq_fops = { .owner = THIS_MODULE, .open = softnet_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};static void *ptype_get_idx(loff_t pos){ struct packet_type *pt = NULL; loff_t i = 0; int t; list_for_each_entry_rcu(pt, &ptype_all, list) { if (i == pos) return pt; ++i; } for (t = 0; t < 16; t++) { list_for_each_entry_rcu(pt, &ptype_base[t], list) { if (i == pos) return pt; ++i; } } return NULL;}static void *ptype_seq_start(struct seq_file *seq, loff_t *pos){ rcu_read_lock(); return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;}static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct packet_type *pt; struct list_head *nxt; int hash; ++*pos; if (v == SEQ_START_TOKEN) return ptype_get_idx(0); pt = v; nxt = pt->list.next; if (pt->type == htons(ETH_P_ALL)) { if (nxt != &ptype_all) goto found; hash = 0; nxt = ptype_base[0].next; } else hash = ntohs(pt->type) & 15; while (nxt == &ptype_base[hash]) { if (++hash >= 16) return NULL; nxt = ptype_base[hash].next; }found: return list_entry(nxt, struct packet_type, list);}static void ptype_seq_stop(struct seq_file *seq, void *v){ rcu_read_unlock();}static void ptype_seq_decode(struct seq_file *seq, void *sym){#ifdef CONFIG_KALLSYMS unsigned long offset = 0, symsize; const char *symname; char *modname; char namebuf[128]; symname = kallsyms_lookup((unsigned long)sym, &symsize, &offset, &modname, namebuf); if (sym
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -