📄 dev.c
字号:
if (dev->master) { skb->real_dev = skb->dev; skb->dev = dev->master; }}static void net_tx_action(struct softirq_action *h){ struct softnet_data *sd = &__get_cpu_var(softnet_data); if (sd->completion_queue) { struct sk_buff *clist; local_irq_disable(); clist = sd->completion_queue; sd->completion_queue = NULL; local_irq_enable(); while (clist) { struct sk_buff *skb = clist; clist = clist->next; BUG_TRAP(!atomic_read(&skb->users)); __kfree_skb(skb); } } if (sd->output_queue) { struct net_device *head; local_irq_disable(); head = sd->output_queue; sd->output_queue = NULL; local_irq_enable(); while (head) { struct net_device *dev = head; head = head->next_sched; smp_mb__before_clear_bit(); clear_bit(__LINK_STATE_SCHED, &dev->state); if (spin_trylock(&dev->queue_lock)) { qdisc_run(dev); spin_unlock(&dev->queue_lock); } else { netif_schedule(dev); } } }}static __inline__ int deliver_skb(struct sk_buff *skb, struct packet_type *pt_prev){ atomic_inc(&skb->users); return pt_prev->func(skb, skb->dev, pt_prev);}#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);static __inline__ int handle_bridge(struct sk_buff **pskb, struct packet_type **pt_prev, int *ret){ struct net_bridge_port *port; if ((*pskb)->pkt_type == PACKET_LOOPBACK || (port = rcu_dereference((*pskb)->dev->br_port)) == NULL) return 0; if (*pt_prev) { *ret = deliver_skb(*pskb, *pt_prev); *pt_prev = NULL; } return br_handle_frame_hook(port, pskb);}#else#define handle_bridge(skb, pt_prev, ret) (0)#endif#ifdef CONFIG_NET_CLS_ACT/* TODO: Maybe we should just force sch_ingress to be compiled in * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions * a compare and 2 stores extra right now if we dont have it on * but have CONFIG_NET_CLS_ACT * NOTE: This doesnt stop any functionality; if you dont have * the ingress scheduler, you just cant add policies on ingress. * */int ing_filter(struct sk_buff *skb) { struct Qdisc *q; struct net_device *dev = skb->dev; int result = TC_ACT_OK; if (dev->qdisc_ingress) { __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd); if (MAX_RED_LOOP < ttl++) { printk("Redir loop detected Dropping packet (%s->%s)\n", skb->input_dev?skb->input_dev->name:"??",skb->dev->name); return TC_ACT_SHOT; } skb->tc_verd = SET_TC_RTTL(skb->tc_verd,ttl); skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS); if (NULL == skb->input_dev) { skb->input_dev = skb->dev; printk("ing_filter: fixed %s out %s\n",skb->input_dev->name,skb->dev->name); } spin_lock(&dev->ingress_lock); if ((q = dev->qdisc_ingress) != NULL) result = q->enqueue(skb, q); spin_unlock(&dev->ingress_lock); } return result;}#endifint netif_receive_skb(struct sk_buff *skb){ struct packet_type *ptype, *pt_prev; int ret = NET_RX_DROP; unsigned short type;#ifdef CONFIG_NETPOLL if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) { kfree_skb(skb); return NET_RX_DROP; }#endif if (!skb->stamp.tv_sec) net_timestamp(&skb->stamp); skb_bond(skb); __get_cpu_var(netdev_rx_stat).total++; skb->h.raw = skb->nh.raw = skb->data; skb->mac_len = skb->nh.raw - skb->mac.raw; pt_prev = NULL; rcu_read_lock();#ifdef CONFIG_NET_CLS_ACT if (skb->tc_verd & TC_NCLS) { skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); goto ncls; }#endif list_for_each_entry_rcu(ptype, &ptype_all, list) { if (!ptype->dev || ptype->dev == skb->dev) { if (pt_prev) ret = deliver_skb(skb, pt_prev); pt_prev = ptype; } }#ifdef CONFIG_NET_CLS_ACT if (pt_prev) { ret = deliver_skb(skb, pt_prev); pt_prev = NULL; /* noone else should process this after*/ } else { skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); } ret = ing_filter(skb); if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) { kfree_skb(skb); goto out; } skb->tc_verd = 0;ncls:#endif handle_diverter(skb); if (handle_bridge(&skb, &pt_prev, &ret)) goto out; type = skb->protocol; list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) { if (ptype->type == type && (!ptype->dev || ptype->dev == skb->dev)) { if (pt_prev) ret = deliver_skb(skb, pt_prev); pt_prev = ptype; } } if (pt_prev) { ret = pt_prev->func(skb, skb->dev, pt_prev); } 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 net_device *backlog_dev, int *budget){ int work = 0; int quota = min(backlog_dev->quota, *budget); struct softnet_data *queue = &__get_cpu_var(softnet_data); unsigned long start_time = jiffies; for (;;) { struct sk_buff *skb; struct net_device *dev; local_irq_disable(); skb = __skb_dequeue(&queue->input_pkt_queue); if (!skb) goto job_done; local_irq_enable(); dev = skb->dev; netif_receive_skb(skb); dev_put(dev); work++; if (work >= quota || jiffies - start_time > 1) break;#ifdef CONFIG_NET_HW_FLOWCONTROL if (queue->throttle && queue->input_pkt_queue.qlen < no_cong_thresh ) { queue->throttle = 0; if (atomic_dec_and_test(&netdev_dropping)) { netdev_wakeup(); break; } }#endif } backlog_dev->quota -= work; *budget -= work; return -1;job_done: backlog_dev->quota -= work; *budget -= work; list_del(&backlog_dev->poll_list); smp_mb__before_clear_bit(); netif_poll_enable(backlog_dev); if (queue->throttle) { queue->throttle = 0;#ifdef CONFIG_NET_HW_FLOWCONTROL if (atomic_dec_and_test(&netdev_dropping)) netdev_wakeup();#endif } local_irq_enable(); return 0;}static void net_rx_action(struct softirq_action *h){ struct softnet_data *queue = &__get_cpu_var(softnet_data); unsigned long start_time = jiffies; int budget = netdev_max_backlog; local_irq_disable(); while (!list_empty(&queue->poll_list)) { struct net_device *dev; if (budget <= 0 || jiffies - start_time > 1) goto softnet_break; local_irq_enable(); dev = list_entry(queue->poll_list.next, struct net_device, poll_list); if (dev->quota <= 0 || dev->poll(dev, &budget)) { local_irq_disable(); list_del(&dev->poll_list); list_add_tail(&dev->poll_list, &queue->poll_list); if (dev->quota < 0) dev->quota += dev->weight; else dev->quota = dev->weight; } else { dev_put(dev); local_irq_disable(); } }out: local_irq_enable(); 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 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(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(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 (dev = dev_base; dev; dev = dev->next) { 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. */static __inline__ struct net_device *dev_get_idx(loff_t pos){ struct net_device *dev; loff_t i; for (i = 0, dev = dev_base; dev && i < pos; ++i, dev = dev->next); return i == pos ? dev : NULL;}void *dev_seq_start(struct seq_file *seq, loff_t *pos){ read_lock(&dev_base_lock); return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN;}void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos){ ++*pos; return v == SEQ_START_TOKEN ? dev_base : ((struct net_device *)v)->next;}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){ if (dev->get_stats) { 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); } else seq_printf(seq, "%6s: No statistics available.\n", dev->name);}/* * 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -