精华内容
下载资源
问答
  • linux网络设备驱动

    千次阅读 2017-02-08 21:44:18
    网络设备驱动架构Linux网络设备驱动程序的体系结构,依次为网络协议接口层,网络设备接口层,提供实际功能的设备驱动功能层以及网络设备与媒介层。 网络协议接口层向网络层协议提供统一的数据包收发接口,不论上层...

    网络设备驱动架构

    Linux网络设备驱动程序的体系结构,依次为网络协议接口层,网络设备接口层,提供实际功能的设备驱动功能层以及网络设备与媒介层。
    网络协议接口层向网络层协议提供统一的数据包收发接口,不论上层协议是ARP,还是IP,都通过dev_queue_xmit()函数发送数据,并通过netif_rx()函数接受数据。
    网络设备接口层向协议接口层提供统一的用于描述具体网络属性和操作的结构体net_device,该结构体是设备驱动功能层中各函数的容器。
    设备驱动功能层的各函数是网络设备接口层net_device数据结构的具体成员,是驱使网络设备硬件完成相应动作的程序,它通过hard_start_xmit() 函数启动发送操作,并通过网络设备上的中断触发操作。
    网络设备与媒介层是完成数据包发送和接收的物理实体,包括网络适配器和具体的传输媒介,网络适配器被设备驱动功能层中的函数在物理上驱动。
    这里写图片描述

    在设计具体的网络设备驱动时,需要完成的主要工作时编写设备驱动功能层的相关函数以填充net_device数据结构的内容并将net_device注册如内核。

    struct net_device {
        char            name[IFNAMSIZ];
        struct hlist_node   name_hlist;
        char            *ifalias;
        /*
         *  I/O specific fields
         *  FIXME: Merge these and struct ifmap into one
         */
        unsigned long       mem_end;
        unsigned long       mem_start;
        unsigned long       base_addr;
        int         irq;
    
        atomic_t        carrier_changes;
    
        /*
         *  Some hardware also needs these fields (state,dev_list,
         *  napi_list,unreg_list,close_list) but they are not
         *  part of the usual set specified in Space.c.
         */
    
        unsigned long       state;
    
        struct list_head    dev_list;
        struct list_head    napi_list;
        struct list_head    unreg_list;
        struct list_head    close_list;
        struct list_head    ptype_all;
        struct list_head    ptype_specific;
    
        struct {
            struct list_head upper;
            struct list_head lower;
        } adj_list;
    
        struct {
            struct list_head upper;
            struct list_head lower;
        } all_adj_list;
    
        netdev_features_t   features;
        netdev_features_t   hw_features;
        netdev_features_t   wanted_features;
        netdev_features_t   vlan_features;
        netdev_features_t   hw_enc_features;
        netdev_features_t   mpls_features;
        netdev_features_t   gso_partial_features;
    
        int         ifindex;
        int         group;
    
        struct net_device_stats stats;
    
        atomic_long_t       rx_dropped;
        atomic_long_t       tx_dropped;
        atomic_long_t       rx_nohandler;
    
    .....
    
        /* for setting kernel sock attribute on TCP connection setup */
    #define GSO_MAX_SIZE        65536
        unsigned int        gso_max_size;
    #define GSO_MAX_SEGS        65535
        u16         gso_max_segs;
    
    #ifdef CONFIG_DCB
        const struct dcbnl_rtnl_ops *dcbnl_ops;
    #endif
        u8          num_tc;
        struct netdev_tc_txq    tc_to_txq[TC_MAX_QUEUE];
        u8          prio_tc_map[TC_BITMASK + 1];
    
    #if IS_ENABLED(CONFIG_FCOE)
        unsigned int        fcoe_ddp_xid;
    #endif
    #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
        struct netprio_map __rcu *priomap;
    #endif
        struct phy_device   *phydev;
        struct lock_class_key   *qdisc_tx_busylock;
        bool            proto_down;
    };
    

    网络设备驱动的注册于注销

    网络设备的注册与注销由register_netdev()ungister_netdev()函数完成。

    net_device结构体的分配和网络设备驱动的注册需在网络设备驱动初始化是进行,而net_device结构体的释放和网络设备驱动的注销在设备或驱动被移除的时候执行。

    net_device_ops结构体是网络设备的一系列硬件操作行数的集合。

    struct net_device_ops {
        int         (*ndo_init)(struct net_device *dev);
        void            (*ndo_uninit)(struct net_device *dev);
        int         (*ndo_open)(struct net_device *dev);
        int         (*ndo_stop)(struct net_device *dev);
        netdev_tx_t     (*ndo_start_xmit)(struct sk_buff *skb,
                              struct net_device *dev);
        netdev_features_t   (*ndo_features_check)(struct sk_buff *skb,
                                  struct net_device *dev,
                                  netdev_features_t features);
        u16         (*ndo_select_queue)(struct net_device *dev,
                                struct sk_buff *skb,
                                void *accel_priv,
                                select_queue_fallback_t fallback);
        void            (*ndo_change_rx_flags)(struct net_device *dev,
                                   int flags);
        void            (*ndo_set_rx_mode)(struct net_device *dev);
        int         (*ndo_set_mac_address)(struct net_device *dev,
                                   void *addr);
        int         (*ndo_validate_addr)(struct net_device *dev);
        int         (*ndo_do_ioctl)(struct net_device *dev,
                                struct ifreq *ifr, int cmd);
        int         (*ndo_set_config)(struct net_device *dev,
                                  struct ifmap *map);
        int         (*ndo_change_mtu)(struct net_device *dev,
                              int new_mtu);
        int         (*ndo_neigh_setup)(struct net_device *dev,
                               struct neigh_parms *);
        void            (*ndo_tx_timeout) (struct net_device *dev);
    
        struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
                                 struct rtnl_link_stats64 *storage);
        struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
    
        int         (*ndo_vlan_rx_add_vid)(struct net_device *dev,
                                   __be16 proto, u16 vid);
        int         (*ndo_vlan_rx_kill_vid)(struct net_device *dev,
                                    __be16 proto, u16 vid);
    #ifdef CONFIG_NET_POLL_CONTROLLER
        void                    (*ndo_poll_controller)(struct net_device *dev);
        int         (*ndo_netpoll_setup)(struct net_device *dev,
                                 struct netpoll_info *info);
        void            (*ndo_netpoll_cleanup)(struct net_device *dev);
    #endif
    
    ......
    
        int         (*ndo_get_lock_subclass)(struct net_device *dev);
        int         (*ndo_set_tx_maxrate)(struct net_device *dev,
                                  int queue_index,
                                  u32 maxrate);
        int         (*ndo_get_iflink)(const struct net_device *dev);
        int         (*ndo_change_proto_down)(struct net_device *dev,
                                 bool proto_down);
        int         (*ndo_fill_metadata_dst)(struct net_device *dev,
                                   struct sk_buff *skb);
        void            (*ndo_set_rx_headroom)(struct net_device *dev,
                                   int needed_headroom);
    };
    

    网络设备的初始化

    网络设备的初始化
    进行硬件上的准备工作,检查网络设备是否存在,如果存在,则检测设备所使用的硬件资源。
    进行软件接口上的准备工作,分配net_device结构体并对齐数据和函数指针成员赋值。
    获得设备的私有信息指针并初始化各成员的值,如果私有信息包括自旋锁或信号量等并发或同步机制,则需对其进行初始化。

    网络设备的打开与释放

    网络设备的打开
    使能设备使用的硬件资源,申请I/O区域,中断和DMA通道等
    调用linux内核提供的netif_start_queue()函数,激活设备发送队列

    网络设备关闭
    调用linux内核提供的netif_stop_queue()函数,停止设备传输包
    释放设备所使用的I/O驱动,中断和DMA资源。

    网络设备驱动包发送

    linux网络子系统在发送数据包时,会用驱动程序提供的hard_start_transmit()函数,该函数用于启动数据包的发送。在设备初始化的时候,这个函数指针需被初始化以指向设备的xxx_tx()函数。

    数据包发送流程
    网络设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区。
    对于以太网,如果有效数据的长度小于以太网冲突检测所要求数据帧的最小长度ETH_ZLEN,则给临时缓冲区的末尾填充0。
    设置硬件的寄存器,驱使网络设备进行数据发送操作。

    数据接收流程

    网络设备接收数据的主要方法是由中断引发设备的中断处理函数,中断处理函数判断中断类型,如果为接收中断,则读取接收到的数据,分配sk_buffer数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区,并调用netif_rx()函数将sk_buffer传递给上层协议。

    网络连接状态

    网络适配器硬件电路可以检测出链路上是否有载波,载波反映了网络的连接是否正常,网络设备驱动可以通过netif_carrier_on()netif_carrier_off()函数改变设备的连接状态,如果驱动检测到连接状态发生变化,也应该以netif_carrier_on()netif_carrier_off()函数显式地通知内核。

    函数netif_carrier_ok()可用于向调用者返回链路上的载波信号是否存在。

    展开全文
  • Linux网络设备驱动概述 一、概述  Linux网络设备驱动程序遵循通用的接口,设计时采用的是面向对象的方法,一个设备就是一个对象(net_device结构)。一个网络设备最基本的方法有初始化、发送和接收...

    Linux网络设备驱动概述

    一、概述     

           Linux网络设备驱动程序遵循通用的接口,设计时采用的是面向对象的方法,一个设备就是一个对象(net_device结构)。一个网络设备最基本的方法有初始化、发送和接收等。

          Linux网络设备驱动程序的体系结构可以分为四层:网络协议接口层、网络设备接口层、设备驱动功能层和网络设备与媒介层,如图1所示。网络设备驱动程序最主要的工作是完成设备驱动功能层。在Linux中,所有网络设备都抽象为一个接口,这个接口提供了对所有网络设备的操作集合。由数据结构struct net_device来表示网络设备在内核中的运行情况,即网络设备接口。它既包括纯软件网络设备接口,如环路(loopback),也包括硬件网络设备接口,如以太网卡。由以dev_base为头指针的设备链来集体管理所有网络设备,该设备链中的每个元素代表一个网络设备接口。数据结构net_device中有很多供系统访问和协议层调用的设备方法,包括初始化,打开和关闭网络设备的open和stop函数,处理数据包发送的hard_start_xmit函数,以及中断处理函数等。

    图1 网络设备驱动体系结构

    二、数据包发送流程

            当网络子系统上层有数据包要发送时,通过调用网络设备驱动中的实现的ndo_start_xmit函数,将要发送的数据包封装在套接字缓冲区skb参数中。在驱动程序的发送数据包函数的具体实现中,它将首先在skb数据包所在主存中的数据块和网络设备内存之间建立一个DMA通道,然后启动该DMA通道将数据包由主存传输到设备内存,之后由网络设备硬件通过网络接口或者天线将数据包发送出去。数据包发送成功后会向处理器发出一个硬件中断,在中断处理程序里做一些善后处理工作,如图2所示。

         

    图2 网络设备驱动程序数据包发送流程

    三、数据包接收流程

            数据包的接收是一个异步的过程,正因为这样,出于系统性能的考虑,绝大部分网络设备都支持数据接收中断,因此在驱动程序中是通过中断处理程序来接收数据包的。由于系统主存与网络设备之间已经建立好DMA通道,所有当有数据包到达网络设备时,数据包会被自动传输到系统主存,此时将产生一个中断信号,从而进入驱动程序的中断处理函数,在中断处理函数里驱动首先会分配一个套接字缓冲区skb来容纳收到的数据包,然后将skb传递到网络子系统的上层代码中,具体传递的过程是驱动程序通过调用netif_rx(skb)函数实现的,上层代码负责释放该skb所占用的内存,如图3所示。

        

    图3 网络设备驱动数据包接收流程

    转自:http://www.cnblogs.com/lknlfy/archive/2012/11/29/2794819.html

    展开全文
  • Linux网络设备驱动架构

    千次阅读 2018-02-01 23:10:09
    Linux网络设备驱动程序体系结构分为四层:网络协议接口层、网络设备接口层、提供实际功能的设备驱动层以及网络设备与媒介层。 (1)网络协议接口层向网络层协议提供统一的数据包收发接口,不论上层协议是ARP还是...

    https://www.cnblogs.com/laoyaodada/p/8397590.html

    Linux网络设备驱动程序体系结构分为四层:网络协议接口层、网络设备接口层、提供实际功能的设备驱动层以及网络设备与媒介层。

    (1)网络协议接口层向网络层协议提供统一的数据包收发接口,不论上层协议是ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过netif_rx()函数接收数据。这一层的存在使得上层协议独立于具体的设备。

    (2)网络设备接口层向协议接口层提供的用于描述具体网络设备属性和操作的结构体net_device,该结构体是设备驱动功能层各函数的容器。

    (3)设备驱动功能层的各函数是网络设备接口层net_device数据结构的具体成员,是驱使网络设备硬件完成相应动作的程序,它通过nto_start_xmit()函数启动发送操作,并通过网络设备上的中断触发接收操作。

    (4)网络设备与媒介层是完成数据包发送和接收的物理实体,包括网络适配器和具体的传输媒介,网络适配器被设备驱动功能层中的函数在物理上驱动。

    驱动工程师的工作:在设计具体的网络设备驱动程序时,需要完成的主要工作是编写设备驱动功能层的相关函数以填充net_device数据结构的内容并将net_device注册入内核。

    1  网络协议接口层

    网络协议接口层最主要的功能是给上层协议提供透明的数据包发送和接收接口。当上层ARP或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_xmit()函数发送该数据包,同时需传递给该函数一个指向struct sk_buff数据结构的指针。dev_queue_xmit()函数的原形为:

    int dev_queue_xmit(struct sk_buff *skb);

    上层通过对数据包的接收也通过向netif_rx()函数传递一个struct sk_buff数据结构的指针来完成。netif_rx()函数的原形为:

    int netif_rx(struct sk_buff *skb);

    sk_buff定义于include/linux/skbuff.h文件中,含义为“套接字缓冲区”用于在Linux网络子系统各层之间传递数据,是Linux网络子系统数据传递的“中枢神经”。

    当发送数据包时,Linux内核的网络处理模块必须建立一个包含要传输的数据包的sk_buff,然后将sk_buff递交给上层,各层在sk_buff中添加不同的协议头直至交给网络设备发送。同样地,当网络设备从网络媒体上接收数据包后,它必须将接收到的数据转换为sk_buff数据结构并传递给上层,各层剥去相应的协议头直至交给用户。

    复制代码
     1 struct sk_buff { 2     struct sk_buff      *next;    // sk_buff是双向链表,所以有前去后继,这是指向后面的sk_buff结构体指针 3     struct sk_buff      *prev;    // 这是指向前一个sk_buff结构体指针 4     ... 5     unsigned int        len,    // 表示数据区的长度(tail-data)与分片结构体数据区的长度之和。 6                 data_len;    // 只表示分片结构体数据区的长度,所以len=(tail - data) + data_len; 7     __u16           mac_len,    // mac报头的长度 8                 hdr_len;    // 用于clone时,表示clone的skb的头长度 9     ...10     __u32           priority;    // 优先级,主要用于QOS11     ...12     __be16          protocol;    // 包的协议类型,标识是IP包还是ARP包还是其他数据包13 14     ...15 16     __be16          inner_protocol;17     __u16           inner_transport_header;    18     __u16           inner_network_header;    19     __u16           inner_mac_header;    20     __u16           transport_header;    // 指向传输包头21     __u16           network_header;    // 指向传输层包头22     __u16           mac_header;    // 指向链路层包头23     /* These elements must be at the end, see alloc_skb() for details.  */24     sk_buff_data_t      tail;25     sk_buff_data_t      end;    // 数据缓冲区的结束地址26     unsigned char       *head,    // 数据缓冲区的开始地址27                 *data;    // 28     ...29 };
    复制代码

    【温馨提示】head和end指向缓冲区的头部和尾部,而data和tail指向实际数据的头部和尾部。每一层会在head和data之间填充协议头,或者在tail和end之间添加协议数据。

     

    下面分析套接字缓冲区涉及的操作函数,Linux套接字缓冲区支持分配、释放、变更等功能函数。

    (1)分配:

    Linux内核中用于分配套接字缓冲区的函数有:

    函数原形

    struct sk_buff *alloc_skb(unsigned int len, gfp_t priority);

    struct sk_buff *dev_alloc_skb(unsigned len);

    函数参数

    len:为数据缓冲区的空间大小,通常以L1_CACHE_BYTES字节(对于ARM为32)对齐

    priority:为内存分配的优先级

    返回值

    成功:返回分配好的sk_buff指针;失败:返回NULL

    【温馨提示】dev_alloc_skb()函数以GFP_ATOMIC优先级进行skb的分配。

    (2)释放:

    Linux内核内部用于释放套接字缓冲区的函数有:

    函数原形

    void kfree_skb(struct sk_buff *skb);

    void dev_kfree_skb(struct sk_buff *skb);

    void dev_kfree_skb_irq(struct sk_buff *skb);

    void dev_kfree_skb_any(struct sk_buff, *skb);

    函数参数

    sk_buff:套接字缓冲区

    Linux内核内部使用kree_skb()函数,而在网络设备驱动程序中则最好用dev_kfree_skb()、dev_kfree_skb_irq()或dev_kfree_skb_any()函数进行套接字缓冲区的释放。其中,dev_kfree_skb()函数用于非中断上下文,dev_kfree_skb_irq()函数用于中断上下文,而dev_kfree_skb_any()函数在中断和非中断上下文都可采用。

    (3)变更

    在Linux内核中可以用如下函数在缓冲区尾部增加数据:

    unsigned char *skb_put(struct sk_buff *skb, unsigned int len);

    它会导致skb->tail后移len(skb->tail += len),而skb->len会增加len的大小(skb->len += len)。通常,在设备驱动的接收数据处理中会调用此函数。

    在Linux内核中可以用以下函数在缓冲区开头增加数据:

    unsigned char *skb_push(struct sk_buff *skb, unsigned int len);

    它会导致skb->data前移len(skb->data -= len),而skb->len会增加len的大小(skb->len += len)。

    对于一个空的缓冲区而言,调用如下函数可以调整缓冲区的头部:

    static inline void skb_reserve(struct sk_buff *skb, int len);

    它会将skb->data和skb->tail同时后移len,执行skb->data += len、skb->tail += len。内核里存在许多这样的代码:

    skb = alloc_skb(len + headspace, GFP_KERNEL);skb_reserve(skb, headspace);skb_put(skb, len);memcpy_fromfs(skb->data, data, len);pass_to_m_protocol(skb);

    上述代码先分配一个全新的sk_buff,接着调用skb_reserve()腾出头部空间,之后调用skb_put()腾出数据空间,然后把数据复制进来,最后把sk_buff传给协议栈。

    2  网络设备接口层

    网络设备接口层的主要功能是为千变万化的网络设备定义统一、抽象的数据结构net_device结构体,以不变应万变,实现多种硬件在软件层次上的统一。

    net_device结构体在内核中指代一个网络设备,它定义在include/linux/netdevice.h文件中,网络设备驱动程序只需通过填充net_device的具体成员并注册net_device即可实现硬件操作函数与内核的挂接。

    (1)全局信息

    char name[IFNAMESIZ];    // name是网络设备名

    (2)硬件信息

    复制代码
    unsigned long mem_end;    // 设备使用的共享内存的结束地址unsigned long mem_start;    // 设备使用的共享内存的起始地址unsigned long base_addr;    // base_addr为网络设备I/O基地址unsigned char irq;    // irq为设备使用的中断号unsigned char if_port;    // 指定多端口设备使用哪一个端口,该字段仅针对多端口设备。例如,如果设备同时支持IF_PORT_10BASE2(同轴电缆)和IF_PORT_10BASET(双绞线),则可使用该字段unsigned char dma;    // dma指定分配给设备的DMA通道
    复制代码

    (3)接口信息

    unsigned short hard_header_len;    // 网络设备的硬件头长度,在以太网设备的初始化函数中,该成员被赋值为ETH_HLEN,即14unsigned short type;    // 接口的硬件类型unsigned mtu;    // 最大传输单元(MTU)unsigned char *dev_addr;    // 用于存放设备的硬件地址,驱动可能提供了设置MAC地址的接口,这会导致用户设置的MAC地址等存入该成员

    dev_addr范例使用代码:

    复制代码
     1 static int moxart_set_mac_address(struct net_device *ndev, void *addr) { 2     struct sockaddr *address = addr; 3  4     if (!is_valid_ether_addr(address->sa_data)) { 5         return -EADDRNOTAVAIL; 6     } 7     memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len); 8     moxart_update_mac_address(ndev); 9 10     return 0;11 }
    复制代码

    接口信息继续:

    unsigned short flags;    // 网络接口标志

    网络接口标志以IFF_开头,部分标志由内核来管理,其他的在接口初始化时被设置以说明设备接口的能力和特性。接口标志包括:

    复制代码
    IFF_UP(当设备被激活并可以开始发送数据包时,内核设置该标志)IFF_AUTOMEDIA(设备可在多种媒介间切换)IFF_BROADCAST(允许广播)IFF_DEBUG(调试模式,可用于控制prink调用的详细程度)IFF_LOOPBACK(回环)IFF_MULTICAST(允许组播)IFF_NOARP(接口不能执行ARP)IFF_POINTOPOINT(接口连接到点到点链路)
    复制代码

    (4)设备操作函数

    const struct net_device_ops *netdev_ops;

    具体内容为:

    复制代码
     1 struct net_device_ops { 2     int         (*ndo_init)(struct net_device *dev); 3     void            (*ndo_uninit)(struct net_device *dev); 4     int         (*ndo_open)(struct net_device *dev); 5     int         (*ndo_stop)(struct net_device *dev); 6     netdev_tx_t     (*ndo_start_xmit) (struct sk_buff *skb, 7                            struct net_device *dev); 8     u16         (*ndo_select_queue)(struct net_device *dev, 9                             struct sk_buff *skb,10                             void *accel_priv,11                             select_queue_fallback_t fallback);12     void            (*ndo_change_rx_flags)(struct net_device *dev,13                                int flags);14     void            (*ndo_set_rx_mode)(struct net_device *dev);15     int         (*ndo_set_mac_address)(struct net_device *dev,16                                void *addr);17     int         (*ndo_validate_addr)(struct net_device *dev);18     int         (*ndo_do_ioctl)(struct net_device *dev,19                             struct ifreq *ifr, int cmd);20 ...21 };
    复制代码

    ndo_open()函数的作用是打开网络接口设备,获得设备需要的I/O地址、IRQ、DMA通道等。stop()函数的作用是停止网络接口设备,与open()函数的作用相反。

    int (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev);

    ndo_start_xmit()函数会启动数据包的发送,当系统调用驱动程序的xmit函数时,需要向其传入一个sk_buff结构体指针,以使得驱动程序能获取从上层传递下来的数据包。

    void (*ndo_tx_timeout) (struct net_device *dev);

    当数据包的发送超时时,ndo_tx_timeout()函数会被调用,该函数需采取重新启动数据包发送过程或重新启动硬件等措施来恢复网络设备到正常状态。

    struct net_device_status* (*ndo_get_stats)(struct net_device *dev);

    ndo_get_status()函数用于获得网络设备的状态信息,它返回一个net_device_stats结构体指针。net_device_stats结构体保存了详细的网络设备流量统计信息,如发送和接收的数据包数、字节数等。

    int (*ndo_do_ioctl) (struct net_device *dev, struct ifreq *ifr, int cmd);int (*ndo_set_config) (struct net_device *dev, struct ifmap *map);int (*ndo_set_mac_address) (struct net_device *dev, void *adddr);

    ndo_do_ioctl()函数用于进行设备特定的I/O控制。

    ndo_set_config()函数用于配置接口,也可用于改变设备的I/O地址和中断号。

    ndo_set_mac_address()函数用于设置设备的MAC地址。

    除了netdev_ops以外,在net_device中还存在类似于ethool_ops、header_ops这样的操作集:

    const struct ethtool_ops *ethool_ops;const struct header_ops *header_ops;

    ethool_ops成员函数与用户空间ethool工具的各个命令选项对应,ethool提供了网卡及网卡驱动管理能力,能够为Linux网络开发人员和管理人员提供对网卡硬件、驱动程序和网络协议栈的设置、查看以及调试等功能。

    header_ops对应于硬件头部操作,主要是完成创建硬件头部和从给定的sk_buff分析出硬件头部等操作。

    (5)辅助成员

    unsigned long trans_start;unsigned long last_rx;

    trans_start记录最后的数据包开始发送时的时间戳,last_rx记录最后一次接收到数据包时的时间戳,这两个时间戳记录的都是jiffies,驱动程序应维护这两个成员。

    通常情况下,网络设备驱动以中断方式接收数据包,而poll_controller()则采用纯轮询方式,另外一种数据接收方式是NAPI(New API),其数据接收流程为“接收中断来临->关闭接收中断->以轮询方式接收所有数据包直到收空->开启接收中断->接收中断来临……”,内核提供了如下与NAPI相关的API:

    void netif_napi_add(struct net_device *dev, struct napi_struct *napi, int (*poll)(struct napi_struct *, int), int weight);void netif_napi_del(struct napi_struct *napi);

    以上两个函数分别用于初始化和移除一个NAPI,netif_napi_add()的poll参数是NAPI要调度执行的轮询函数。

    static inline void napi_enable(struct napi_struct *n);static inline void napi_disable(struct napi_struct *n);

    以上两个函数分别用于使能和禁止NAPI调度。

    该函数用于检查NAPI是否可以调度,而napi_schedule()函数用于调度轮询实例的运行。

    其原形为:

    static inline void napi_schedule(struct napi_struct *n);

    在NAPI处理完成的时候应该调用:

    void napi_complete(struct napi_struct *n);

    3  设备驱动功能层

    net_device结构体的成员(属性和net_device_ops结构体中的函数指针)需要被设备驱动功能层赋予具体的数值和函数。对于具体的设备xxx,工程师应该编写相应的设备驱动功能层的函数,这些函数形如xxx_open()、xxx_stop()、xxx_tx()、xxx_hard_header()、xxx_get_stats()和xxx_tx_timeout()等。

    由于网络数据包的接收可由中断引发,设备驱动功能层的另一个主体部分将是中断处理函数,它负责读取硬件上接收到的数据包并传送给上层协议,因此可能包含xxx_interrupt()和xxx_rx()函数,前者完成中断类型判断等基本工作,后者则需完成数据包的生成及将其递交给上层等复杂工作。

    对于特定的设备,我们还可以定义相关的私有数据和操作,并封装为一个私有信息结构体xxx_private,让其指针赋值给net_device的私有成员。在xxx_private结构体中可包含设备的特殊属性和操作、自旋锁与信号量、定时器以及统计信息等,这都由工程师自定义。在驱动中,要用到私有数据的时候,则使用在netdevice.h中定义的接口:

    static inline void *netdev_priv(const struct net_device *dev);

    比如在驱动drivers/net/ethernet/davicom/dm9000.c的dm9000_probe()函数中,使用alloc_etherdev(sizeof(struct board_info))分配网络设备,board_info结构体就成了这个网络设备的私有数据,在其他函数中可以简单地提取这个私有数据。例如:

    1 static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) {2     unsigned long flags;3     board_info_t *db = netdev_priv(dev);4     ...5 }
    展开全文
  • linux网络设备驱动的结构

    千次阅读 2013-11-04 10:55:26
    第十六章linux 网络设备驱动的结构 中描述了对应linux 网络设备的驱动结构。其中,net_device 是设备驱动功能层中的各种函数的容器。向上提供统一的用于描述网络设备属性和操作的结构体

    <Linux设备驱动开发详解第二版>第十六章linux 网络设备驱动的结构 中描述了对应linux 网络设备的驱动结构。其中,net_device 是设备驱动功能层中的各种函数的容器。向上提供统一的用于描述网络设备属性和操作的结构体

     

    展开全文
  • Linux网络设备驱动架構學習(一)

    千次阅读 2013-08-09 15:29:08
    Linux网络设备驱动架構分析() Linux 网络设备驱动的结构  Linux 网络设备驱动程序的体系结构如下图所示,从上到下可以划分为 4 层,依次为网络协议接口层、网络设备接口层、提供实际功能的设备驱动功能层以及网络...
  • 编写Linux网络设备驱动(上)

    千次阅读 2011-10-12 23:12:58
    编写Linux网络设备驱动(上)《编写Linux网络设备驱动(上)》来自:刘建文 | 学术半·IT歌·文作者:刘建文关键字:Linux 驱动程序永久链接地址:http://arttech.us/y-2011/writing-network-device-driver-a.html
  • 一、协议栈层次对比 二.Linux网络子系统  Linux网络子系统的顶部是系统调用接口层。它为用户空间提供的应用程序提供了一种访问内核网络子系统的方法...然后是设备无关层,它提供了协议与设备驱动通信的通用接口
  • Linux网络设备驱动架構學習(二)

    千次阅读 2013-08-09 16:04:14
    Linux网络设备驱动架構學習(二) 接下來會從以下幾個方面介紹網絡設備驅動的編寫流程: 1、網絡設備的註冊與註銷 2、網絡設備的初始化 3、網絡設備的打開與釋放 4、網絡數據發送流程 5、網絡數據接收流程 6、網絡連...
  • 协议简介 虽然对于网络的正式介绍一般都参考了 OSI(Open Systems Interconnection)模型,但是本文对 Linux 中...链路层是指提供对物理层访问的设备驱动程序,这可以是各种介质,例如串口链路或以太网设备。链路层上
  • Preface  Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计。  Linux内核采用分层结构... 在Linux内核中,对网络部分按照网络协议层、网络设备层、设备驱动功能层和网络媒介
  • Linux网络设备驱动(一) _驱动模型

    千次阅读 2017-03-28 09:51:47
    Linux素来以其强大的网络功能著名,同时, 网络设备也作为三大设备之一, 成为Linux驱动学习中必不可少的设备类型, 此外, 由于历史原因, Linux并没有强制对网络设备贯彻其"一切皆文件"的思想, 网络设备不以/dev下的设备...
  • Linux网络设备驱动概述-(dm9000-1)

    千次阅读 2014-02-25 14:26:51
    ... Linux网络设备驱动程序遵循通用的接口,设计时采用的是面向对象的方法,一个设备就是一个对象(net_device结构)。一个网络设备最基本的方法有初始化、发送和接收等。  Linux网络设备驱
  • linux 网络设备驱动之alloc_etherdev

    千次阅读 2018-11-14 19:39:55
    最近在看网络驱动时,发现这个函数:   struct net_device *netdev; netdev = alloc_etherdev(sizeof(synopGMACPciNetworkAdapter)); 顺着这个函数进行追踪: #define alloc_etherdev(sizeof_priv) alloc_...
  • linux网络设备驱动之实质篇

    千次阅读 2012-04-10 18:13:41
    在讲解linux内核自身携带的网络设备驱动程序之前,先讲解一下网络设备模型,知道要做些什么。 对于网络设备驱动,主要目的就是接受数据和发送数据。而人们把网络设备的体系结构就分为上面四层,就是为了更好...
  • Linux网络设备驱动程序——alloc_netdev()与alloc_etherdev() 分类: 我自己的学习日志 Linux驱动相关2013-11-07 20:27 115人阅读 评论(0) 收藏 举报 Linux 网络设备驱动alloc_netdev与alloc_e ...
  • 1 引言 Linux网络设备驱动程序是Linux操作系统网络应用中的一个重要的组成部分,分析其运行机理,对于设计Linux网络应用程序是很有帮助的。我们可以在网络驱动程序这一级做一些与应用相关联的特殊事情,例如,在设计...
  • 从上到下:网络协议接口层-->网络设备结构层-->设备驱动实现层-->网络设备与媒介层   记忆方法: 分三层,1、最上面理解为我们用的网络传输方法,就是网络协议,2、最下面就是物理硬件,即...
  • Linux设备驱动之网络设备驱动

    千次阅读 2011-04-14 22:03:00
    网络堆栈是硬件中独立出来的部分,主要用来支持TCP/IP等多种协议,而网络设备驱动层是连接网络堆栈协议层和网络硬件的中间层。网络设备驱动程序的主要功能是:(1)模块加载或内核启动相关的初始化处理(2)清除模块时的...
  • 本课程是linux驱动开发的第11个课程,主要内容是linux的网络驱动的介绍,首先讲述了网络设备驱动接口和之前讲的2种的不同,然后以一个虚拟网卡驱动源码学习了网卡驱动的框架,后分析了一个实际网卡DM9000的驱动细节...
  • Linux无线设备驱动
  • Linux的网络系统主要是基于BSD Unix 的socket机制, 访问网络设备驱动程序不需要使用设备节点。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统内部支持对发送数据和接收数据的缓存,...
  • linux网络设备理解

    千次阅读 2016-11-15 21:16:39
    网络层次linux网络设备驱动与字符设备和块设备有很大的不同。 1. 字符设备和块设备对应/dev下的一个设备文件。而网络设备不存在这样的设备文件。网络设备使用套接字socket访问,虽然也使用read,write系统调用,但...
  • 其范围从协议无关层(例如通用 socket 层接口或设备层)到各种具体的网络协议实现。 协议简介 对于网络的理论介绍一般都采用 OSI(Open Systems Interconnection)模型,但是Linux网络栈...
  • Linux设备驱动工程师之路——网络设备驱动基本原理和框架 K-Style 转载请注明来自于衡阳师范学院08电2 K-Style http://blog.csdn.net/ayangke,QQ:843308498 邮箱:yangkeemail@qq.com   1.Linux网络子系统  ...
  • 浅谈 Linux 内核开发之网络设备驱动

    千次阅读 2017-12-12 20:49:21
    转载自 https://www.ibm.com/developerworks/cn/linux/l-cn-networkdriver/个人最近在学习网络设备驱动,本文从宏观上概括,略去了繁琐复杂的细节,易于初学者理解。这里Mark一下,和同样从事驱动开发的兄弟们进行...
  • Linux字符设备驱动

    千次阅读 2017-08-27 18:36:35
    1. Linux设备类型Linux内核中的设备可分为三类:字符设备、块设备和网络设备。 字符设备(Character device):适合面向字符的数据交换,因其数据传输量较低。对这种设备的读写是按字符进行的,而且这些字符是连续...
  • 嵌入式linux驱动主要分为三...字符设备驱动块设备驱动网络设备驱动 字符设备驱动: APP:open、read、write。。。 驱动:drv_open、drv_read、drv_write。。。 框架: (1)主设备号 (2)file_operation结构体 (3)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 126,823
精华内容 50,729
关键字:

linux网络设备驱动

linux 订阅