《Linux Device Drivers》 第十七章 网络驱动程序——note

《Linux Device Drivers》 第十七章 网络驱动程序——note

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

  • 基本介绍
    • 第三类是标准的网络接口Linux设备,本章介绍的内核,其余的交互网络接口描述
    • 网络接口,必须使用特定的内核数据结构本身注册,与外部分组交换数据线打电话时准备
    • 经常使用的文件上的网络接口操作是没有意义的,因此在它们身上无法体现Unix的“一切都是文件”的思想
    • 网络驱动程序异步自外部世界的数据包
    • 网络设备向内核请求把外部获得的数据包发送给内核
    • Linux内核中的网络子系统被设计成全然与协议无关
    • 在网络世界中使用术语“octet”指一组8个的数据位。它是能为网络设备和协议所能理解的最小单位
    • 协议头(header)是在数据包中的一系列字节,它将通过网络子系统的不同层
  • 连接到内核
    • loopback.c、plip.c和e100.c
    • 设备注冊
      • 驱动程序对每一个新检測到的接口,向全局的网络设备链表中插入一个数据结构
      • <linux/netdevice.h>
      • struct net_device
      • struct net_device *alloc_netdev(int sizeof_priv, const char *name, void (*setup) (struct net_device *));
        • name是接口的名字,这个名字能够使用类似printf中%d的格式,内核将用下一个可用的接口号替代%d
      • <linux/etherdevie.h>
        • struct net_device *alloc_etherdev(int sizeof_priv);
      • 光纤通道设备使用alloc_fcdev(<linux/fcdevice.h>)
      • FDDI设备使用alloc_fddidev(<linux/fddidevice.h>)
      • 令牌环设备使用alloc_trdev(<linux/trdevice.h>)
      • register_netdev函数
    • 初始化每一个设备
      • example
        • ether_setup(dev);
        • dev->open = open_function;
        • dev->stop = release_function;
        • dev->set_config = config_function;
        • dev->hard_start_xmid = tx_function;
        • dev->do_ioctl = ioctl_function;
        • dev->get_stats = stats_function;
        • dev->rebuild_header = rebuild_header_function;
        • dev->hard_header = header_function;
        • dev->tx_timeout = tx_timeout_function;
        • dev->watchdog_timo = timeout;
        • dev->flags |= IFF_NOARP;
        • dev->features |= NETIF_F_NO_CSUM;
        • dev->hard_header_cache = NULL;
      • priv = netdev_priv(dev);
    • 模块的卸载
      • unregister_netdev函数从系统中删除接口
      • free_netdev函数将net_device结构返回给系统

  • net_device结构细节
    • 全局信息
      • char name[IFNAMSIZ];
      • unsigned long state;
      • struct net_device *next;
      • int (*init) (struct net_device *dev);
    • 硬件信息
      • unsigned long rmem_end;
      • unsigned long rmem_start;
      • unsigned long mem_end;
      • unsigned long mem_start;
      • unsigned long base_addr;
      • unsigned char irq;
      • unsigned char if_port;
      • unsigned char dma;
    • 接口信息
      • drivers/net/net_init.c
      • void ltalk_setup(struct net_device *dev);
      • void fs_setup(struct net_device *dev);
      • void fddi_setup(struct net_device *dev);
      • void hippi_setup(struct net_device *dev);
      • void tr_setup(struct net_device *dev);
      • unsigned short hard_header_len;
        • 对以太网接口,该值是14
      • unsigned mtu;
        • 最大传输单元,以太网的MTU是1500个octet
      • unsigned long tx_queue_len;
      • unsigned short type;
        • ARP使用type成员推断接口所支持的硬件地址类型
        • <linux/if_arp.h>
      • unsigned char addr_len;
      • unsigned char broadcast[MAX_ADDR_LEN];
      • unsigned char dev_addr[MAX_ADDR_LEN];
      • unsigned short flags;
      • int features;
        • 该标志成员是一个位掩码
        • IFF_前缀表示“接口标志”,有效的标志定义在<linux/if.h>
    • 设备方法
      • 网络接口的设备方法可划分为两个类型:主要的和可选的
      • 基本方法
        • int (*open) (struct net_device *dev);
        • int (*stop) (struct net_device *dev);
        • int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev);
        • int (*hard_header) (struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);
        • int (*rebuild_header) (struct sk_buff *skb);
        • void (*tx_timeout) (struct net_device *dev);
        • struct net_device_stats *(*get_stats) (struct net_device *dev);
        • int (*set_config) (struct net_device *dev, struct ifmap *map);
      • 可选方法
        • int (*poll) (struct net_device *dev, int *quota);
        • void (*poll_controller) (struct net_device *dev);
        • int (*do_ioctl) (struct net_device *dev, struct ifreq *ifr, int cmd);
        • void (*set_multicast_list) (struct net_device *dev);
        • int (*set_mac_address) (struct net_device *dev, void *addr);
        • int (*change_mtu) (struct net_device *dev, int net_mtu);
        • int (*header_cache) (struct neighbour *neigh, struct hh_cache *hh);
        • int (*header_cache_update) (struct hh_cache *hh, struct net_device *dev, unsigned char *haddr);
        • int (*hard_header_parse) (struct sk_buff *skb, unsigned char *haddr);
    • 工具成员
      • unsigned long trans_start;
      • unsigned long last_rx;
      • int watchdog_timeo;
      • void *priv;
      • struct dev_mc_list *mc_list;
      • int mc_count;
      • spinlock_t xmit_lock;
      • int xmit_lock_owner;
  • 打开和关闭
    • 在使用ifconfig向接口赋予地址时,要运行两个任务
      • 首先,通过ioctl(SIOCSIFADDR)赋予地址
      • 然后,通过ioctl(SIOCSIFFLAGS)设置dev->flag中的IFF_UP标志以打开接口
    • 对设备而言,无需对ioctl(SIOCSIFADDR)做不论什么工作。后一个命令会调用设备的open方法
    • 在接口被关闭时,ifconfig使用ioctl(SIOSIFFLAGS)来清除IFF_UP标志,然后调用stop函数
    • 此外。还要运行其它一些步骤
      • 首先,在接口有够和外界通讯之前,要将硬件地址(MAC)从硬件设备拷贝到dev->dev_addr
      • 应该启动接口的传输队列
        • void netif_start_queue(struct net_device *dev);
  • 数据包传输
    • 不管何时内核要传输一个数据包,它都会调用驱动程序的hard_start_transmit函数将数据放入外发队列
    • 内核处理的每一个数据包位于一个套接字缓冲区结构(sk_buff)中。该结构定义在<linux/skbuff.h>中
    • 传递经全hard_start_xmit的套接字缓冲区包括了物理数据包,并拥有完整的传输层数据包头
    • 该传输函数仅仅运行了对数据包的一致性检查。然后通过硬件相关的函数数据传输
    • 假设运行成功,则hard_start_xmit返回0
    • 控制并发传输
      • 通过net_device结构中的一个自旋锁获得并发调用时的保护
      • 实际的硬件接口是异步数据传输包的,并且可用来保存外发数据包的存储空间很有限
      • void netif_wake_queu(struct net_device *dev);
        • 通知网络系统可再次開始数据传输包
      • void netif_tx_disable(struct net_device *dev);
        • 禁止数据包的传送
    • 传输超时
      • 假设当前的系统时间超过设备的trans_start时间至少一个超时周期,网络层将终于调用驱动程序的tx_timeout函数
    • Scatter/Gather I/O
      • 在网络上为传输工作创建数据包的过程,包含了组装多个数据片段的过程
      • 假设负责发送数据包的网络接口实现了分散/聚焦I/O,则数据包就不用组装成一个大的数据包
      • 分散/聚焦I/O还能用“零拷贝”的方法。把网络数据直接从用户缓冲区内传输出来
      • 假设在device结构中的feature成员内设置了NETIF_F_SG标志位。内核才将分散的数据包传递给hard_start_xmit函数
      • struct skb_frag_struct
        • struct page *page;
        • __u16 page_offset;
        • __u16 size;
  • 数据包的接收
    • 从网络上接收数据要比数据传输复杂一点。由于必须在原子上下文中分配一个sk_buff并传递给上层处理
    • 网络驱动程序实现了两种模式接收数据包:中断驱动方式和轮询方式
    • 过程
      • 第一步是分配一个保存数据包的缓冲区
        • dev_alloc_skb
      • 检查dev_alloc_skb函数的返回值
      • 一旦拥有一个合法的skb指针,则调用memcpy将数据包数据复制到缓冲区内
      • 最后。驱动程序更新其统计计数器
    • 接收数据包过程中的最后一个步骤由netif_rx运行
  • 中断处理例程
    • 接口在两种可能的事件下中断处理器
      • 新数据包到达
      • 外发数据包的传输已经完毕
    • 通常中断例程通过检查物理设备中的状态寄存器,以区分新数据包到达中断和传输数据完成中断
    • 传输结束时。统计信息要被更新,并且要将套接字缓冲区返回全系统
      • dev_kfree_skb(struct sk_buff *skb);
      • dev_kfree_skb_irq(struct sk_buff *skb);
      • dev_kfree_skb_any(struct sk_buff *skb);
  • 不使用接收中断
    • 为了能提高Linux在宽带系统上的性能。网络子系统开发人员创建了第二种基于轮询方法的接口(称之为NAPI)
    • 停止使用中断会减轻处理器的负荷
    • struct net_device的poll成员必须设置为驱动程序的轮询函数
    • 当接口通知数据到达的时候,中断程序不能处理该数据包,相反它还要禁止接收中断,而且告诉内核。从如今開始启动轮询接口
    • 用netif_receive_skb函数将数据包传递给内核,而不是使用netif_rx
    • 调用netif_rx_complete关闭轮询函数
  • 链路状态的改变
    • 大多数涉及实际的物理连接的网络技术提供载波状态信息,载波的存在意味着硬件功能是正常的
    • void netif_carrier_off(struct net_device *dev);
    • void netif_carrier_on(struct net_device *dev);
    • int netif_carrier_ok(struct net_device *dev);
      • 用来检測当前的载波状态
  • 套接字缓冲区
    • <linux/skbuff.h>
    • 重要的成员
      • struct net_device *dev
      • union { /* … */ } h;
      • union { /* … */ } nh;
      • union { /* … */ } mac;
      • unsigned char *head;
      • unsigned char *data;
      • unsigned char *tail;
      • unsigned char *end;
      • unsigned int len;
      • unsigned int data_len;
      • unsigned char ip_summed;
      • unsigned char pkt_type;
      • shinfo (struct sk_buff *skb);
      • unsigned int shinfo(skb)->nr_frags;
      • skb_frag_t shinfo(skb)->frags;
    • 操作套接字缓冲区的函数
      • struct sk_buff *alloc_skb(unsigned int len, int priority);
      • struct sk_buff *dev_alloc_skb(unsigned int len);
      • 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);
      • unsigned char *skb_put(struct sk_buff *skb, int len);
      • unsigned char *__skb_put(struct sk_buff *skb, int len);
      • unsigned char *skb_push(struct sk_buff *skb, int len);
      • unsigned char *__skb_push(struct sk_buff *skb, int len);
      • int skb_tailroom(struct sk_buff *skb);
      • int skb_headroom(struct sk_buff *skb);
      • void skb_reserve(struct sk_buff *skb, int len);
      • unsigned char *skb_pull(struct sk_buff *skb, int len);
      • int skb_is_nonlinear(struct sk_buff *skb);
      • int skb_headlen(struct sk_buff *skb);
      • void *kmap_skb_frag(skb_frag_t *frag);
      • void kunmap_skb_frag(void *vaddr);
  • MAC地址解析
    • 在以太网中使用ARP
      • ARP由内核维护,而以太网接口不须要做不论什么特殊工作就能支持ARP
    • 重载ARP
      • 假设设备希望使用经常使用的硬件头,而不执行ARP,则须要重载默认的dev->hard_header函数
    • 非以太网头
      • 硬件头中除目标地址之外,还包括其它一些信息。当中最重要的是通信协议
      • drivers/net/appletalk/cops.c
      • drivers/net/irda/smc_ircc.c
      • drivers/net/pp_generic.c
  • 定制ioctl命令
    • 当为某个套接字使用ioctl系统调用时。命令号是定义在<linux/sockios.h>中的某个符号
    • 函数sock_ioctl直接调用一个协议相关的函数
    • 不论什么协议层不能识别的ioctl命令都会传递到设备层
    • 这些设备相关的ioctl命令从用户空间接受第三个參数。即一个struct ifreq *指针
      • <linux/if.h>
  • 统计信息
    • 驱动程序须要的最后一个函数是get_stats,这个函数返回设备统计结构的指针
    • struct net_device_stats
      • unsigned long rx_packets;
      • unsigned long tx_packets;
      • unsigned long rx_bytes;
      • unsigned long tx_bytes;
      • unsigned long rx_errors;
      • unsigned long tx_errors;
      • unsigned long rx_dropped;
      • unsigned long tx_dropped;
      • unsigned long collisions;
      • unsigned long multicast;
  • 组播
    • 对以太网而言,组播地址在目标地址的第一个octet的最低位设置为1,而全部设备板卡将自己的硬件地址的对应位清零
    • 内核在随意给定时刻均要跟踪组播地址
    • 驱动程序实现组播清单的方法。在某种程序上依赖于底层硬件的工作方式
    • 通常来说,考虑组播时。硬件可划分为三类
      • 不有处理组播的接口
      • 可以区分组播数据包和其它数据包的接口
      • 可以为组播地址进行硬件检測的接口
    • 对组播的内核支持
      • 对组播数据包的支持由例如以下几项组成:一个设备函数、一个数据结构以及若干设备标志
      • void (*dev_set_multicast_list) (struct net_device *dev);
      • struct dev_mc_list *dev->mc_list;
      • int dev->mc_count;
      • <linux/netdevice.h>
      • struct dev_mc_list
        • struct dev_mc_list *next
        • __u8 dmi_addr[MAX_ADDR_LEN];
        • unsigned char dmi_addrlen;
        • int dmi_users;
        • int dmi_gusers;
  • 其它知识点具体解释
    • 对介质无关接口的支持
      • 介质无关接口(Media Independent Interface, MII)是一个IEEE802.3标准,它描写叙述了以太网收发器是怎样与网络控制器连接的
      • <linux/mii.h>
      • int (*mdio_read) (struct net_device *dev, int phy_id, int location);
      • void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
      • drivers/net/mii.c
    • ethtool支持
      • ethtool是为系统管理员提供的用于控制网络接口的工具
      • 仅仅有当驱动程序支持ethtool时。使用ethtool才干控制包含速度、介质类型、双工操作、DMA设置、硬件检验、LAN唤醒操作在内的很多接口參数
      • http://sf.net/projects/gkernel/
      • <linux/ethtool.h>
      • struct ethtool_ops
    • Netpoll
      • 它出现的目的是让内核在网络和I/O子系统尚不能完整可用时,依旧能发送和接收数据包
      • 用于网络控制台和远程内核调试
      • 实现netpoll的驱动程序须要实现poll_controller函数,作用是在缺少设备中断时。还能对控制器响应

版权声明:本文博客原创文章,博客,未经同意,不得转载。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/117744.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • C# Sort排序

    C# Sort排序List的Sort方法排序有三种结果1,0,-1分别表示大于,等于,小于。1.对于数值类型的List(List),直接使用Sort进行排序。ListscoreList=newList(){89,100,78,23,67};scoreList.Sort();//默认按升序排列,相当于:scoreList.Sort((x,y)=>x.CompareTo(y))scoreLis

  • Android+jacoco实现代码覆盖率最正确的实现方式,没有之一!

    Android+jacoco实现代码覆盖率最正确的实现方式,没有之一!前言:jacoco是JavaCodeCoverage的缩写,是Java代码覆盖率统计的主流工具之一。关于jacoco的原理介绍的文章在网上有很多,感兴趣的同学可以去找别的博客看看,我这里不做赘述。它的作用是在安卓项目的代码覆盖率统计使用了jacoco的离线插桩方式,在测试前先对文件进行插桩,然后生成插过桩的class或jar包,测试(单元测试、UI测试或者手工测试等)插过桩的class和jar包后,会生成动态覆盖信息到文件,最后统一对覆盖信息进行处理,并生成报告。在我接到这个需求,需要统计开发人.

  • php 数组动态添加实现代码(最土团购系统的价格排序)

    最近在实现最土团购系统的价格排序功能,需要对$oc数组进行扩展,经过测试用下面的方法即可。核心代码如下:因为是多条件查询所以需要先判断是否为空,然后再添加到数组里面。推荐:http://www.

    2021年12月27日
  • js除法取整数取余数_java中取余中的余数怎么取

    js除法取整数取余数_java中取余中的余数怎么取取整1.取整//丢弃小数部分,保留整数部分parseInt(5/2)  //22.向上取整//向上取整,有小数就整数部分加1Math.ceil(5/2)  //33.向下取整//向下取整,丢弃小数部分Math.floor(5/2)  //24四舍五入//四舍五入Math.round(5/2)  //3取余//取余6%4 …

  • MBus协议详解(三)[通俗易懂]

    MBus协议详解(三)[通俗易懂]这节主要集中在MBus协议物理层和数据链路层的硬件实现上,其关键点包括:1、由主到从传输的时候电压的调制;2、由从到主传输的时候电流脉冲的调制;3、总线短路保护。1、由主到从传输的时候电压的调制如上图所示,信号在-27V、0V、+15V上进行调制,采用2个MOS管P201、P202,+15V电压通过稳压器降压到+12V。由主到从传输数据的时…

    2022年10月15日
  • ttl低电平接大电阻_3.4 TTL门电路

    ttl低电平接大电阻_3.4 TTL门电路3.4TTL门电路1.双极性三极管的开关特性(静态)图1在数字电路中,三极管作为开关元件,主要工作在饱和和截止两种开关状态,放大区只是极短暂的过渡状态。2.三极管的开关时间(动态特性)图2(1)开启时间ton:三极管从截止到饱和所需的时间。ton=td+trtd:延迟时间tr:上升时间(2)关闭时间toff:三极管从饱和到截止所需的时间。toff=ts+tf…

    2022年10月30日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号