• Linux网络设备驱动框架


     /************************************************************************************

    *本文为个人学习记录,如有错误,欢迎指正。

    *本文参考资料: 

    *        http://www.cnblogs.com/xiaojiang1025/archive/2017/03/28/6486267.html

    *        https://blog.csdn.net/zdy0_2004/article/details/79234386

    ************************************************************************************/

     1. 网络设备驱动框架总体简介

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

    (1)网络协议接口层

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

    (2)网络设备接口层

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

    (3)设备驱动功能层

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

    (4)网络设备与媒介层

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

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

    2. 相关数据结构

    (1)struct sk_buff

    sk_buff是网络驱动框架中信息的载体, 是网络分层模型中对数据进行层层打包以及层层解包的载体。

     427 struct sk_buff {
     428         /* These two members must be first. */
     429         struct sk_buff          *next;   //sk_buff是双向链表,所以有前去后继,这是指向后面的sk_buff结构体指针
     430         struct sk_buff          *prev;   //这是指向前一个sk_buff结构体指针 
     432         ktime_t                 tstamp;
     434         struct sock             *sk;
     435         struct net_device       *dev;    //对应的net_device
     443         char                    cb[48] __aligned(8);
     445         unsigned long           _skb_refdst;
     449         unsigned int            len,     //表示数据区的长度(tail-data)与分片结构体数据区的长度之和
     450                                 data_len;//只表示分片结构体数据区的长度,所以len=(tail - data) + data_len
     451         __u16                   mac_len, //mac报头的长度
     452                                 hdr_len;
     473         __be16                  protocol;//包的协议类型,标识是IP包还是ARP包还是其他数据包
     534         __u16                   inner_transport_header;
     535         __u16                   inner_network_header;
     536         __u16                   inner_mac_header;
     537         __u16                   transport_header; //指向传输包头
     538         __u16                   network_header;   //指向传输层包头
     539         __u16                   mac_header;       //指向链路层包头
     540         /* These elements must be at the end, see alloc_skb() for details.  */
     541         sk_buff_data_t          tail;             //指向当前数据包的尾地址, 随着各个网络层的加工而变化
     542         sk_buff_data_t          end;              //数据缓冲区的结束地址
     543         unsigned char           *head,            //数据缓冲区的开始地址
     544                                 *data;            //data指向当前数据包的首地址, 随着各个网路层的加工而变化
     545         unsigned int            truesize;
     546         atomic_t                users;
     547 };
    struct sk_buff

     (2)struct net_device

    Linux内核中使用 net_device 来描述一个网络设备,net_device是设备接口层的核心, 也是编写网络驱动核心的对象。

    1160 struct net_device {
    1167         char                    name[IFNAMSIZ];//网络设备的名称, 网络设备被载入后会出现在ifconfig中, 比如默认的eth0就是这个
    1179         unsigned long           mem_end;        //网络设备所使用的共享内存起始地址
    1180         unsigned long           mem_start;      //网络设备所使用的共享内存结束地址
    1181         unsigned long           base_addr;      //表示网络设备的IO基地址
    1182         int                     irq;            //设备使用的中断号
    1189         unsigned long           state;
    1190 
    1191         struct list_head        dev_list;
    1192         struct list_head        napi_list;
    1193         struct list_head        unreg_list;
    1194         struct list_head        close_list;
    1210         netdev_features_t       features;       //用户层可以修改的特征
    1212         netdev_features_t       hw_features;    //用户层不能修改的特征
    1214         netdev_features_t       wanted_features;
    1243         const struct net_device_ops *netdev_ops;//网络设备的操作方法集
    1244         const struct ethtool_ops *ethtool_ops;  //ethtool的方法集
    1245         const struct forwarding_accel_ops *fwd_ops;
    1248         const struct header_ops *header_ops;    //协议头操作集
    1250         unsigned int            flags;  /* interface flags (a la BSD)   */
    1251         unsigned int            priv_flags; /* Like 'flags' but invisible to userspace.
    1252                                              * See if.h for definitions. */
    1253         unsigned short          gflags;                   
    1254         unsigned short          padded; /* How much padding added by alloc_netdev() */
    1256         unsigned char           operstate; /* RFC2863 operstate */
    1257         unsigned char           link_mode; /* mapping policy to operstate */
    1259         unsigned char           if_port;        /* Selectable AUI, TP,..*/
    1260         unsigned char           dma;            /* DMA channel          */
    1262         unsigned int            mtu;    /* interface MTU value          */
    1263         unsigned short          type;   /* interface hardware type      */
    1264         unsigned short          hard_header_len;        /* hardware hdr length  */
    1270         unsigned short          needed_headroom;
    1271         unsigned short          needed_tailroom;
    1274         unsigned char           perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
    1275         unsigned char           addr_assign_type; /* hw address assignment type */
    1276         unsigned char           addr_len;       /* hardware address length      */
    1289         struct kset             *queues_kset;
    1386         int                     watchdog_timeo; /* used by dev_watchdog() */
    1480 };
    struct net_device

     (3)struct net_device_ops

     网络设备的操作方法集。

    1002 struct net_device_ops {
    1003         int          (*ndo_init)(struct net_device *dev);
    1004         void         (*ndo_uninit)(struct net_device *dev);
    1005         int          (*ndo_open)(struct net_device *dev);//打开网络接口设备,获得设备需要的I/O地址、IRQ、DMA通道等
    1006         int          (*ndo_stop)(struct net_device *dev);//停止网络接口设备,与open()函数的作用相反
    1007         netdev_tx_t  (*ndo_start_xmit) (struct sk_buff *skb,struct net_device *dev);//启动数据包的发送,当系统调用驱动程序的xmit函数时,需要向其传入一个sk_buff结构体指针,以使得驱动程序能获取从上层传递下来的数据包
    1013         void         (*ndo_change_rx_flags)(struct net_device *dev,int flags);
    1015         void         (*ndo_set_rx_mode)(struct net_device *dev);
    1016         int          (*ndo_set_mac_address)(struct net_device *dev,void *addr);//用于设置设备的MAC地址
    1018         int          (*ndo_validate_addr)(struct net_device *dev);
    1019         int          (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);//用于进行设备特定的I/O控制
    1021         int          (*ndo_set_config)(struct net_device *dev, struct ifmap *map);       //用于配置接口,也可用于改变设备的I/O地址和中断号
    1023         int          (*ndo_change_mtu)(struct net_device *dev, int new_mtu);
    1025         int          (*ndo_neigh_setup)(struct net_device *dev,struct neigh_parms *);
    1027         void         (*ndo_tx_timeout) (struct net_device *dev);//当数据包的发送超时时,ndo_tx_timeout()函数会被调用,该函数需采取重新启动数据包发送过程或重新启动硬件等措施来恢复网络设备到正常状态
    1028 
    1148 };

    3. 相关API

    (1)分配/释放net_device

    //linux/etherdevice.h
    /**
     * 分配及初始化net_device对象()
     * @sizeof_priv - 私有数据大小(单位:字节数)
     * 返回值:失败:NULL, 成功:net_device对象的首地址
     */
    struct net_device *alloc_etherdev(int sizeof_priv);
    
    //linux/netdevice.h
    /**
     * 分配及初始化net_device对象
     * @int sizeof_priv - 私有数据大小(单位:字节数)
     * @const char *name - 物理接口名("名称%d")
     * @unsigned char name_assign_type - NET_NAME_UNKNOWN
     * @void (*setup)(struct net_device *) - 初始化函数
     * 返回值:失败:NULL成功:net_device对象的首地址
     */
    struct net_device *alloc_netdev(int sizeof_priv, const char *name,unsigned char name_assign_type,void (*setup)(struct net_device *));
    
    
    //释放
    void free_netdev(struct net_device *dev);

    (2)以太网的初始化

    在初始化一个以太网设备的时候应该被调用, 它的主要作用就是针对以太网标准对net_device对象进行初始化。

    void ether_setup(struct net_device *dev);

    (3)注册/注销net_device

    //注册
    int register_netdev(struct net_device *dev);
    //注销
    void unregister_netdev(struct net_device *dev);

     (4)开始/停止发送队列

    //开启发送队列
    void netif_start_queue(struct net_device *dev)
    //停止发送队列
    void netif_stop_queue(struct net_device *dev)

    4. 网络设备的中断处理函数

    中断处理函数

    是网络设备媒介层相设备驱动功能层发送数据的接口, 网卡接收到数据是通过中断的方式上报的, 所以网络驱动中的中断处理函数就是第一时间队接收到的数据进行处理的地方,这个函数最终一定要调用netif_rx()将收到的数据上报到协议接口层。 

     5. 网络设备驱动实例

    转载一篇DM9000驱动分析的文章,写得非常详细,感谢作者的贡献。 Linux DM9000网卡驱动程序完全分析

  • 相关阅读:
    捉BUG记(To Catch a Bug)
    发布一个简单的knockout-easyui绑定库
    笔记:Hyper-V上Centos 6.5分辨率调整问题解决笔记
    Asp.net中HttpRequest.Params与Reques.Item之异同
    Oracle必须死之奇怪的ORA-06502错误
    centos7 搭建bitcoin/usdt 节点服务
    webpack安装配置
    centos7 rsyslog
    nginx+fpm 开机自启
    centos7下 PHP添加pdo_myql扩展
  • 原文地址:https://www.cnblogs.com/linfeng-learning/p/9547356.html
Copyright © 2020-2023  润新知