网络设备使用队列来管理数据帧的输出流量,每个队列可以使用队列策略算法来安排发送帧的优先级,使发送过程更高效。详细的队列策略处理属于流量控制子系统的内容,本人还没来的及研究,这里先不涉及。本章讨论没配置队列策略的情况下设备的发送队列。

数据关联:

dev->dev_queue->qdisc

网络设备->发送队列->队列策略

每个网络设备可以有自己的发送队列,队列数量可以自定义。

每个发送队列可以有自己的队列策略,队列策略数量可以自定义。

网络设备可以有自己的发送队列,也可以没有自己的发送队列(这种情况下发送队列长度为零)。

1、一般虚拟网络设备没有自己的发送队列。对于没有发送队列的网络设备,其直接调用自己的发送函数进行发送,不需要由发包软中断来调度发送。如果发送失败,就丢弃报文,不进行缓存。

2、有自己的发送队列的网络设备,如果发送失败,会缓存到发送队列,等待资源可用后再重新发送,这时报文缓存在队列策略管理的优先级队列中。其发送报文是由发包软中断进行调度来发送的。跟NAPI接收相似,NAPI接收时调度使用NAPI,发送时调度使用队列策略qdisc。没有配置队列策略的发送队列会使用默认的队列策略pfifo_fast。

数据结构定义:

1、在struct net_device结构体中定义如下几个发送对列相关的字段:

struct net_device

{

/*指向设备的发送队列列表*/

struct netdev_queue *_tx;

/*发送队列的个数*/

unsigned int num_tx_queues;

/*现在使用的发送队列个数*/

unsigned int real_num_tx_queues;

/*设备使用的默认队列策略*/

struct Qdisc *qdisc;

/*每个发送队列的最大长度*/

unsigned long tx_queue_len;

/*发送队列的全局锁*/

spinlock_t tx_global_lock;

}

2、发送队列结构体

struct netdev_queue

{

/*队列所属网络设备*/

struct net_device *dev;

/*发送队列对应的队列策略结构体链表*/

struct Qdisc *qdisc;

/*队列的运行状态*/

unsigned long state;

struct Qdisc *qdisc_sleeping;

spinlock_t _xmit_lock ____cacheline_aligned_in_smp;

/*持有该队列锁的cpu id*/

int xmit_lock_owner;

/*本次队列最进一次开始发送的时间戳*/

unsigned long trans_start;

/*队列对发送报文的统计信息*/

unsigned long tx_bytes;

unsigned long tx_packets;

unsigned long tx_dropped;

} ____cacheline_aligned_in_smp;

3、发送队列策略结构体

struct Qdisc

{

/*报文入队操作函数*/

int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);

/*报文出队操作*/

struct sk_buff * (*dequeue)(struct Qdisc *dev);

unsigned flags;

#define TCQ_F_BUILTIN 1

#define TCQ_F_THROTTLED 2

#define TCQ_F_INGRESS 4

#define TCQ_F_CAN_BYPASS 8

#define TCQ_F_MQROOT 16

#define TCQ_F_WARN_NONWC (1 << 16)

/*申请队列策略内存中为字节对齐所预留的长度*/

int padded;

/*队列策略自己的一些操作函数,

*申请队列策略时根据这些函数来初始化队列策略的一些字段

*/

struct Qdisc_ops *ops;

struct qdisc_size_table *stab;

struct list_head list;

u32 handle;

u32 parent;

/*引用计数*/

atomic_t refcnt;

struct gnet_stats_rate_est rate_est;

int (*reshape_fail)(struct sk_buff *skb,

struct Qdisc *q);

void *u32_node;

/* This field is deprecated, but it is still used by CBQ

* and it will live until better solution will be invented.

*/

struct Qdisc *__parent;

/*所属发送队列*/

struct netdev_queue *dev_queue;

/*有报文发送时把队列策略挂到softnet_data->out_queue上*/

struct Qdisc *next_sched;

/*指向最近一次发送失败的报文,下次发送时优先发送该报文*/

struct sk_buff *gso_skb;

/*

* For performance sake on SMP,

*we put highly modified fields at the end

*/

/*队列策略的运行调度状态*/

unsigned long state;

/*队列策略的默认缓存报文的队列*/

struct sk_buff_head q;

/*一些统计信息*/

struct gnet_stats_basic_packed bstats;

struct gnet_stats_queue qstats;

};

流量控制系统中每种队列策略都提供了自己的函数,供数据链路层调用来完成队列的操作。

enqueue:向队列加入一个报文。

dequeue:从队列中摘一个报文。

4、发送队列的操作函数:struct Qdisc_ops

{

struct Qdisc_ops *next;

const struct Qdisc_class_ops *cl_ops;

/*队列策略的名字*/

char id[IFNAMSIZ];

/*队列策略的私有数据结构体大小*/

int priv_size;

/*入队操作函数*/

int (*enqueue)(struct sk_buff *, struct Qdisc *);

/*出队操作函数*/

struct sk_buff * (*dequeue)(struct Qdisc *);

/*初始化操作函数*/

int (*init)(struct Qdisc *, struct nlattr *arg);

/*把队列策略和发送队列关联的操作函数*/

void (*attach)(struct Qdisc *);

struct module *owner;

};

网络设备发送队列的创建

在申请设备时创建dev的发送队列,如果调用alloc_netdev()时,默认创建一个队列。要创建多个发送队列,调用alloc_netdev_mq().

#define alloc_netdev(sizeof_priv, name, setup) \

alloc_netdev_mq(sizeof_priv, name, setup, 1)struct net_device *alloc_netdev_mq(int sizeof_priv,

const char *name,

void (*setup)(struct net_device *),

unsigned int queue_count)

{

struct netdev_queue *tx;

struct net_device *dev;

......

tx = kcalloc(queue_count,

sizeof(struct netdev_queue),

GFP_KERNEL);

dev->_tx = tx;

dev->num_tx_queues = queue_count;

dev->real_num_tx_queues = queue_count;

netdev_init_queues(dev);

......

return dev;

}

发送队列策略的创建struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,

struct Qdisc_ops *ops)

{

void *p;

struct Qdisc *sch;

unsigned int size;

int err = -ENOBUFS;

/* ensure that the Qdisc and

*the private data are 32-byte aligned

*/

size = QDISC_ALIGN(sizeof(*sch));

/*申请队列策略时,队列结构体下紧接着

*放着队列策略的私有结构体

*/

size += ops->priv_size + (QDISC_ALIGNTO - 1);

p = kzalloc(size, GFP_KERNEL);

if (!p)

{

goto errout;

}

sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p);

/*设置padded 字段*/

sch->padded = (char *) sch - (char *) p;

INIT_LIST_HEAD(&sch->list);

skb_queue_head_init(&sch->q);

sch->ops = ops;

/*根据ops 里定义的函数来初始化队列策略的一些函数指针*/

sch->enqueue = ops->enqueue;

sch->dequeue = ops->dequeue;

sch->dev_queue = dev_queue;

dev_hold(qdisc_dev(sch));

atomic_set(&sch->refcnt, 1);

return sch;

errout:

return ERR_PTR(err);

}

根据给出的ops,给发送队列来创建一个默认的队列策略struct Qdisc * qdisc_create_dflt(struct net_device *dev,

struct netdev_queue *dev_queue,

struct Qdisc_ops *ops,

unsigned int parentid)

{

struct Qdisc *sch;

/*申请一个队列策略*/

sch = qdisc_alloc(dev_queue, ops);

if (IS_ERR(sch))

{

goto errout;

}

sch->parent = parentid;

/*调用ops->init来初始化队列策略*/

if (!ops->init || ops->init(sch, NULL) == 0)

{

return sch;

}

qdisc_destroy(sch);

errout:

return NULL;

}

linux队列数据结构,网络设备发送队列相关数据结构及其创建函数 (linux网络子系统学习 第十节 )...相关推荐

  1. 人生最好的php,mysql,linux,redis,docker等相关技术经典面试题,新手收藏学习,持续更新中。。。

    php面试题 1.写出你能想到的所有HTTP返回状态值,并说明用途(比如:返回404表示找不到页面) # 200:服务器请求成功 # 301:永久重定向,旧网页已被新网页永久替代 # 302:表示临时 ...

  2. linux 在某个core上的中断 affinity c语言函数,Linux中断处理体系结构

    各种的异常的C处理函数可以分为5类,他们分布在不同的文件中. 1.在arch/arm/kernel/trapsc.c中 未定义指令异常,总入口函数为do_undefinstr. 2.在arch/arm ...

  3. android socket 发送byte_如何正确地创建和销毁网络通讯程序中的Socket类的对象实例...

    软件项目实训及课程设计指导--如何正确地创建和销毁软件应用系统中网络通讯中的Socket类的对象实例 1.基于TCP/IP协议的Socket通信相关的基础知识 (1)TCP/IP(Transmissi ...

  4. Gem5模拟器,如何在linux系统中查看内存、CPU、硬盘、进程、网络等信息(十二)

    虽然说,这个记录的是与Linux相关的操作,每次查每次忘,必须写一个来归总一下,以免我漫山遍野找命令.但是不想新开一一个主题,再加上确实是在运行模拟器时会关注这方面的信息,就把这一节搁这儿啦. 常见的 ...

  5. linux多级反馈队列的实现,多级反馈队列调度算法的实现

    <多级反馈队列调度算法的实现>由会员分享,可在线阅读,更多相关<多级反馈队列调度算法的实现(16页珍藏版)>请在人人文库网上搜索. 1.学生实习报告课程名称_ 数据结构与数据处 ...

  6. linux lvm的操作手册_pvcreate_vgcreate_lvcreate_相关

    作者微信:15013593099 欢迎交流 linux lvm的操作手册_pvcreate_vgcreate_lvcreate_相关 一. 前言 每个Linux使用者在安装Linux时都会遇到这样的困 ...

  7. 【Linux 内核】CFS 调度器 ⑥ ( CFS 调度器就绪队列 cfs_rq | Linux 内核调度实体 sched_entity | “ 红黑树 “ 数据结构 rb_root_cached )

    文章目录 一.CFS 调度器就绪队列 cfs_rq 二.Linux 内核调度实体 sched_entity 三." 红黑树 " 数据结构 rb_root_cached 一.CFS ...

  8. 数据结构——栈与队列相关题目

    数据结构--栈与队列相关题目 232. 用栈实现队列 思路 225. 用队列实现栈 1.两个队列实现栈 2.一个队列实现栈 20. 有效的括号 思路 1047. 删除字符串中的所有相邻重复项 思路 1 ...

  9. linux定时器tinner,第三章 套接字相关数据结构--基于Linux3.10

    本章是对socket通信过程中使用到的比较重要的据结构罗列和意义的阐述,在阅读其它层的代码前,先来看几个重要的数据结构,这几个数据结构贯串四层模型. 3.1 socket对应的内核结构体 在用户空间使 ...

最新文章

  1. python【蓝桥杯vip练习题库】ADV-279矩阵乘法
  2. MYSQL 取中位数
  3. 初识jvm-1.Java类的加载机制
  4. 北京大学孙俊教授课题组深度视频研究室招收2021级博士生
  5. 【javascript】checkbox——类似邮箱全选功能
  6. Kronos Research推出结合WOO质押机制的新资管产品规模已达1500万美元
  7. 移动端车牌识别(前端识别、后端识别)的区别分析
  8. 函数计算如何粘合云服务,提供端到端解决方案
  9. Office 365 On MacOS 系列——安装 O365 其他组件
  10. Android:使用SharedPreferences进行数据存储
  11. 使用drawBitmapMesh扭曲图像
  12. 自动接听电话的另一种思路(只需要root权限)
  13. Oracle数据库同义词创建
  14. word字体号对应的磅数
  15. WordPress使用邮箱服务功能
  16. matlab模拟化学反应,Matlab环境下化学反应动力学的MonteCarlo模拟
  17. android studio静态界面设计,2.3 使用Android Studio 简单设计UI界面
  18. LGP970刷机心得
  19. 人类简史--经典语句摘录
  20. 适合所有手环的app_Redmi Watch体验:手环终结者?

热门文章

  1. tomcat假死排查-数据连接池耗尽
  2. win10+ubuntu18.04双系统安装/大集合
  3. FaceBook推出的Android图片加载库-Fresco
  4. 2016年天猫手机双11玩法曝光
  5. [C++] 集合元素(如字符串)的排列组合
  6. 小白快速入手微信小程序
  7. p-value,q-value,FDR
  8. 【ESP32 WiFi篇(三)】ESP32 TCP服务端、客户端
  9. 【闪电侠学netty】第6章 客户端与服务端双向通信
  10. [JS 分析] 邮箱地址加密 [email protected]