zoukankan      html  css  js  c++  java
  • 深入理解linux网络技术内幕读书笔记(九)--中断与网络驱动程序

    接收到帧时通知驱动程序

    轮询

    例如,内核可以持续读取设备上的一个内存寄存器,或者当一个定时器到期时就回头检查哪个寄存器。

    中断

    此时,当特定事件发生时,设备驱动程序会代表内核指示设备产生硬件中断。内核将中断其他活动,然后调用一个驱动程序
    所注册的处理函数,以满足设备的需要。当事件是接收到一个帧时,处理函数就会把该帧排入队列某处,然后通知内核。


    中断处理程序

    表9-1 一些与软件中断及硬件中断相关API
    函数/宏描述
    in_interrupt处于软硬件中断中,且抢占功能是关闭的
    in_softirq处于软件中断中
    in_irq处于硬件中断中
    softirq_pending软件中断未决
    local_softirq_pending本地软件中断未决
    __raise_softirq_irqoff设置与输入的软IRQ类型相关联的标识,将该软IRQ标记为未决
    raise_softirq_irqoff先关闭硬件中断,再调用__raise_softirq_irqoff,再恢复其原有状态
    raise_softirq
    __local_bh_enable
    local_bh_enable
    local_bh_disable
    local_irq_disable
    local_irq_enable
    local_irq_save
    local_irq_restore
    spin_lock_bh
    spin_unlock_bh


    抢占功能

    • preempt_disable()
      为当前任务关闭抢占功能。可以重复调用,递增一个引用计数器。
    • preempt_enable()
    • preempt_enable_no_resched()
      开启抢占功能。preempt_enable_no_reched()只是递减一个引用计数器,使得其值为0时,可以让抢占再度开启。


    下半部函数

    内核2.4版本以后的下半部函数: 引入软IRQ

    对并发的唯一限制就是何时,在一个CPU上每个软IRQ都只能有一个实例运行。
    新式的软IRQ模型只有10种模型(include/linux/interrupt.h):


     1:  /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
     2:     frequency threaded job scheduling. For almost all the purposes
     3:     tasklets are more than enough. F.e. all serial device BHs et
     4:     al. should be converted to tasklets, not to softirqs.
     5:   */
     6:  
     7:  enum
     8:  {
     9:    HI_SOFTIRQ=0,
    10:    TIMER_SOFTIRQ,
    11:    NET_TX_SOFTIRQ,
    12:    NET_RX_SOFTIRQ,
    13:    BLOCK_SOFTIRQ,
    14:    BLOCK_IOPOLL_SOFTIRQ,
    15:    TASKLET_SOFTIRQ,
    16:    SCHED_SOFTIRQ,
    17:    HRTIMER_SOFTIRQ,
    18:    RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */
    19:  
    20:    NR_SOFTIRQS
    21:  };
    

    网络代码如何使用软IRQ

    网络子系统在net/core/dev.c中注册接收发送软中断:

    open_softirq(NET_TX_SOFTIRQ, net_tx_action);
    open_softirq(NET_RX_SOFTIRQ, net_rx_action);

     1:  /*
     2:   *    Initialize the DEV module. At boot time this walks the device list and
     3:   *    unhooks any devices that fail to initialise (normally hardware not
     4:   *    present) and leaves us with a valid list of present and active devices.
     5:   *
     6:   */
     7:  
     8:  /*
     9:   *       This is called single threaded during boot, so no need
    10:   *       to take the rtnl semaphore.
    11:   */
    12:  static int __init net_dev_init(void)
    13:  {
    14:    int i, rc = -ENOMEM;
    15:  
    16:    BUG_ON(!dev_boot_phase);
    17:  
    18:    if (dev_proc_init())
    19:        goto out;
    20:  
    21:    if (netdev_kobject_init())
    22:        goto out;
    23:  
    24:    INIT_LIST_HEAD(&ptype_all);
    25:    for (i = 0; i < PTYPE_HASH_SIZE; i++)
    26:        INIT_LIST_HEAD(&ptype_base[i]);
    27:  
    28:    if (register_pernet_subsys(&netdev_net_ops))
    29:        goto out;
    30:  
    31:    /*
    32:     *  Initialise the packet receive queues.
    33:     */
    34:  
    35:    for_each_possible_cpu(i) {
    36:        struct softnet_data *sd = &per_cpu(softnet_data, i);
    37:  
    38:        memset(sd, 0, sizeof(*sd));
    39:        skb_queue_head_init(&sd->input_pkt_queue);
    40:        skb_queue_head_init(&sd->process_queue);
    41:        sd->completion_queue = NULL;
    42:        INIT_LIST_HEAD(&sd->poll_list);
    43:        sd->output_queue = NULL;
    44:        sd->output_queue_tailp = &sd->output_queue;
    45:  #ifdef CONFIG_RPS
    46:        sd->csd.func = rps_trigger_softirq;
    47:        sd->csd.info = sd;
    48:        sd->csd.flags = 0;
    49:        sd->cpu = i;
    50:  #endif
    51:  
    52:        sd->backlog.poll = process_backlog;
    53:        sd->backlog.weight = weight_p;
    54:        sd->backlog.gro_list = NULL;
    55:        sd->backlog.gro_count = 0;
    56:    }
    57:  
    58:    dev_boot_phase = 0;
    59:  
    60:    /* The loopback device is special if any other network devices
    61:     * is present in a network namespace the loopback device must
    62:     * be present. Since we now dynamically allocate and free the
    63:     * loopback device ensure this invariant is maintained by
    64:     * keeping the loopback device as the first device on the
    65:     * list of network devices.  Ensuring the loopback devices
    66:     * is the first device that appears and the last network device
    67:     * that disappears.
    68:     */
    69:    if (register_pernet_device(&loopback_net_ops))
    70:        goto out;
    71:  
    72:    if (register_pernet_device(&default_device_ops))
    73:        goto out;
    74:  
    75:    open_softirq(NET_TX_SOFTIRQ, net_tx_action);
    76:    open_softirq(NET_RX_SOFTIRQ, net_rx_action);
    77:  
    78:    hotcpu_notifier(dev_cpu_callback, 0);
    79:    dst_init();
    80:    dev_mcast_init();
    81:    rc = 0;
    82:  out:
    83:    return rc;
    84:  }
    85:  
    86:  subsys_initcall(net_dev_init);
    

    softnet_data结构

    每个CPU都有其队列,用来接收进来的帧。数据结构为:


     1:   /*
     2:   * Incoming packets are placed on per-cpu queues
     3:   */
     4:  struct softnet_data {
     5:    struct Qdisc        *output_queue;
     6:    struct Qdisc        **output_queue_tailp;
     7:    struct list_head    poll_list;
     8:    struct sk_buff      *completion_queue;
     9:    struct sk_buff_head process_queue;
    10:  
    11:    /* stats */
    12:    unsigned int        processed;
    13:    unsigned int        time_squeeze;
    14:    unsigned int        cpu_collision;
    15:    unsigned int        received_rps;
    16:  
    17:  #ifdef CONFIG_RPS
    18:    struct softnet_data *rps_ipi_list;
    19:  
    20:    /* Elements below can be accessed between CPUs for RPS */
    21:    struct call_single_data csd ____cacheline_aligned_in_smp;
    22:    struct softnet_data *rps_ipi_next;
    23:    unsigned int        cpu;
    24:    unsigned int        input_queue_head;
    25:    unsigned int        input_queue_tail;
    26:  #endif
    27:    unsigned        dropped;
    28:    struct sk_buff_head input_pkt_queue;
    29:    struct napi_struct  backlog;
    30:  };
    

  • 相关阅读:
    linux通过源码安装nodejs
    设置npm的镜像源
    ubuntu手动安装PhantomJS
    h2数据库的简单使用
    xampp启动失败 Apache shutdown unexpectedly
    phpqrcode实现二维码(含图片)
    php 使用 rabbitmq
    rabbitMQ linux安装
    rabbitmq的web管理界面无法使用guest用户登录
    linux安装使用xdebug
  • 原文地址:https://www.cnblogs.com/mosp/p/3558638.html
Copyright © 2011-2022 走看看