- 浏览: 321770 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
JQ_AK47:
...
Linux下直接发送以太包 -
winsen2009:
谢谢分享,如果能再来一个列子就更好了,刚接触看完还是不懂的用
UNPv1_r3读书笔记: SCTP编程
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,
严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
5.11.3 HTB一些操作函数 5.11.3.1 转换函数 /* TODO: maybe compute rate when size is too large .. or drop ? */ // 将长度转换为令牌数 static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate, int size) { // 根据大小计算合适的槽位 int slot = size >> rate->rate.cell_log; // 如果超过了255, 限制为255 if (slot > 255) { cl->xstats.giants++; slot = 255; } return rate->data[slot]; } // HTB哈希计算, 限制哈希结果小于16, 因为只有16个HASH表, 这个大小是定死的 static inline int htb_hash(u32 h) { #if HTB_HSIZE != 16 #error "Declare new hash for your HTB_HSIZE" #endif h ^= h >> 8; /* stolen from cbq_hash */ h ^= h >> 4; return h & 0xf; } 5.11.3.2 查询函数 /* find class in global hash table using given handle */ // 根据句柄handle查找HTB节点 static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch) { // HTB私有数据结构 struct htb_sched *q = qdisc_priv(sch); struct hlist_node *p; struct htb_class *cl; if (TC_H_MAJ(handle) != sch->handle) return NULL; // 根据句柄计算哈希值, 然后遍历该哈希链表 hlist_for_each_entry(cl, p, q->hash + htb_hash(handle), hlist) { // 查找类别ID和句柄handle相等的HTB节点返回 if (cl->classid == handle) return cl; } return NULL; } 5.11.3.3 分类函数 /** * htb_classify - classify a packet into class * * It returns NULL if the packet should be dropped or -1 if the packet * should be passed directly thru. In all other cases leaf class is returned. * We allow direct class selection by classid in priority. The we examine * filters in qdisc and in inner nodes (if higher filter points to the inner * node). If we end up with classid MAJOR:0 we enqueue the skb into special * internal fifo (direct). These packets then go directly thru. If we still * have no valid leaf we try to use MAJOR:default leaf. It still unsuccessfull * then finish and return direct queue. */ #define HTB_DIRECT (struct htb_class*)-1 // 获取HTB类别结构的ID static inline u32 htb_classid(struct htb_class *cl) { // 如果类别结构有效(非空而且不是直接通过), 返回其类别ID, 否则返回TC_H_UNSPEC // 表示没指定类别ID return (cl && cl != HTB_DIRECT) ? cl->classid : TC_H_UNSPEC; } // HTB分类操作, 对数据包进行分类, 然后根据类别进行相关操作 // 返回NULL表示没找到, 返回-1表示是直接通过(不分类)的数据包 static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) { // HTB私有结构 struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl; // 分类规则处理结果 struct tcf_result res; // 分类过滤规则表 struct tcf_proto *tcf; int result; /* allow to select class by setting skb->priority to valid classid; note that nfmark can be used too by attaching filter fw with no rules in it */ // 如果数据包优先权值就等于流控节点和句柄handle, 属于根节点操作, 直接处理 if (skb->priority == sch->handle) return HTB_DIRECT; /* X:0 (direct flow) selected */ // 查找和数据包优先权值对应的HTB叶子节点, 找到则返回 if ((cl = htb_find(skb->priority, sch)) != NULL && cl->level == 0) return cl; // 以下处理是没有找到和skb->priority直接对应的HTB叶子节点, 应该说实际应用中大部分 // 都是skb->priority为0的, 所以一般都会运行到这里 *qerr = NET_XMIT_BYPASS; tcf = q->filter_list; // 进行标准TC分类, 分类方法由TC命令定义的规则来实现 while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) { #ifdef CONFIG_NET_CLS_ACT // 定义了可对分类结果进行动作的内核选项的情况 switch (result) { case TC_ACT_QUEUED: case TC_ACT_STOLEN: // 发送成功 *qerr = NET_XMIT_SUCCESS; // 丢包 case TC_ACT_SHOT: return NULL; } #elif defined(CONFIG_NET_CLS_POLICE) // 没定义NET_CLS_ACT而定义了NET_CLS_POLICE的情况 // 如果分类结果是TC_POLICE_SHOT, 属于HTB直接处理 if (result == TC_POLICE_SHOT) return HTB_DIRECT; #endif // 如果分类结果为空 if ((cl = (void *)res.class) == NULL) { // 如果分类结果的ID等于流控句柄, 直接处理 if (res.classid == sch->handle) return HTB_DIRECT; /* X:0 (direct flow) */ // 再根据结果的类别ID查找HTB叶子节点, 找不到的话退出循环 if ((cl = htb_find(res.classid, sch)) == NULL) break; /* filter selected invalid classid */ } // 分类找到的情况, 如果是叶子节点, 直接返回 if (!cl->level) return cl; /* we hit leaf; return it */ // 如果不是叶子节点,更新过滤表, 用该类别的内部过滤规则表重新搜索, // 从这里就可看出HTB的多层次结构, 由上层向下层细化 /* we have got inner class; apply inner filter chain */ tcf = cl->filter_list; } // 循环外是没找到分类的情况 /* classification failed; try to use default class */ // 用缺省类别ID查找, 看是否定义了缺省类别 cl = htb_find(TC_H_MAKE(TC_H_MAJ(sch->handle), q->defcls), sch); // 没找到或者是只是中间节点, 返回直接处理 if (!cl || cl->level) return HTB_DIRECT; /* bad default .. this is safe bet */ return cl; } 5.11.3.4 激活类别 /** * htb_activate - inserts leaf cl into appropriate active feeds * * Routine learns (new) priority of leaf and activates feed chain * for the prio. It can be called on already active leaf safely. * It also adds leaf into droplist. */ // 激活类别结构, 将该类别节点作为数据包提供者, 而数据类别表提供是一个 // 有序表, 以RB树形式实现 static inline void htb_activate(struct htb_sched *q, struct htb_class *cl) { BUG_TRAP(!cl->level && cl->un.leaf.q && cl->un.leaf.q->q.qlen); // 如果类别的prio_activity参数为0才进行操作, 非0表示已经激活了 if (!cl->prio_activity) { // prio_activity是通过叶子节点的prio值来设置的, 至少是1, 最大是1<<7, 非0值 // leaf.aprio保存当前的leaf.prio cl->prio_activity = 1 << (cl->un.leaf.aprio = cl->un.leaf.prio); // 进行实际的激活操作 htb_activate_prios(q, cl); // 根据leaf.aprio添加到指定的优先权位置的丢包链表 list_add_tail(&cl->un.leaf.drop_list, q->drops + cl->un.leaf.aprio); } } /** * htb_activate_prios - creates active classe's feed chain * * The class is connected to ancestors and/or appropriate rows * for priorities it is participating on. cl->cmode must be new * (activated) mode. It does nothing if cl->prio_activity == 0. */ // 激活操作, 建立数据提供树 // cl->prio_activity为0时就是一个空函数, 不过从前面看prio_activity似乎是不会为0的 static void htb_activate_prios(struct htb_sched *q, struct htb_class *cl) { // 父节点 struct htb_class *p = cl->parent; // prio_activity是作为一个掩码, 可应该只有一位为1 long m, mask = cl->prio_activity; // 在当前模式是HTB_MAY_BORROW情况下进入循环, 某些情况下这些类别是可以激活的 // 绝大多数情况p和mask的初始值应该都是非0值 while (cl->cmode == HTB_MAY_BORROW && p && mask) { // 备份mask值 m = mask; while (m) { // 掩码取反, 找第一个0位的位置, 也就是原来最低为1的位的位置 // prio越小, 等级越高, 取数据包也是先从prio值小的节点取 int prio = ffz(~m); // 清除该位 m &= ~(1 << prio); // p是父节点, 所以inner结构肯定有效, 不会使用leaf结构的 // 如果父节点的prio优先权的数据包的提供树已经存在, 在掩码中去掉该位 if (p->un.inner.feed[prio].rb_node) /* parent already has its feed in use so that reset bit in mask as parent is already ok */ mask &= ~(1 << prio); // 将该类别加到父节点的prio优先权提供数据包的节点树中 htb_add_to_id_tree(p->un.inner.feed + prio, cl, prio); } // 父节点的prio_activity或上mask中的置1位, 某位为1表示该位对应的优先权的 // 数据可用 p->prio_activity |= mask; // 循环到上一层, 当前类别更新父节点, 父节点更新为祖父节点 cl = p; p = cl->parent; } // 如果cl是HTB_CAN_SEND模式, 将该类别添加到合适的ROW中 // 此时的cl可能已经不是原来的cl了,而是原cl的长辈节点了 if (cl->cmode == HTB_CAN_SEND && mask) htb_add_class_to_row(q, cl, mask); // 如果cl是HTB_CANT_SEND模式则不进行任何操作了, 因为是阻塞状态 } /** * htb_add_to_id_tree - adds class to the round robin list * * Routine adds class to the list (actually tree) sorted by classid. * Make sure that class is not already on such list for given prio. */ static void htb_add_to_id_tree(struct rb_root *root, struct htb_class *cl, int prio) { struct rb_node **p = &root->rb_node, *parent = NULL; // RB树是有序表, 根据类别ID排序, 值大的到右节点, 小的到左节点 // 循环, 查找树中合适的位置插入类别节点cl while (*p) { struct htb_class *c; parent = *p; c = rb_entry(parent, struct htb_class, node[prio]); if (cl->classid > c->classid) p = &parent->rb_right; else p = &parent->rb_left; } // 进行RB树的插入操作, RB树标准函数操作 rb_link_node(&cl->node[prio], parent, p); rb_insert_color(&cl->node[prio], root); } /** * htb_add_class_to_row - add class to its row * * The class is added to row at priorities marked in mask. * It does nothing if mask == 0. */ static inline void htb_add_class_to_row(struct htb_sched *q, struct htb_class *cl, int mask) { // 将cl层次对应的ROW的row_mask或上新的mask, 表示有对应prio的数据了 q->row_mask[cl->level] |= mask; // 循环mask, 将cl插入mask每一位对应的prio的树中 while (mask) { // prio是mask中最低为1的位的位置 int prio = ffz(~mask); // 清除该位 mask &= ~(1 << prio); // 添加到具体的RB树中 htb_add_to_id_tree(q->row[cl->level] + prio, cl, prio); } } 5.11.3.4 关闭类别 /** * htb_deactivate - remove leaf cl from active feeds * * Make sure that leaf is active. In the other words it can't be called * with non-active leaf. It also removes class from the drop list. */ // 将类别叶子节点从活动的数据包提供树中去掉 static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl) { BUG_TRAP(cl->prio_activity); // 关闭 htb_deactivate_prios(q, cl); // 类别的活性值prio_activity清零 cl->prio_activity = 0; // 将类别节点从drop表断开并重新初始化list结构 list_del_init(&cl->un.leaf.drop_list); } /** * htb_deactivate_prios - remove class from feed chain * * cl->cmode must represent old mode (before deactivation). It does * nothing if cl->prio_activity == 0. Class is removed from all feed * chains and rows. */ static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl) { // 类别节点的父节点 struct htb_class *p = cl->parent; // 类别结构的优先权活性值作为掩码, 如果是0的话本函数相当于空函数 long m, mask = cl->prio_activity; // 在当前模式是HTB_MAY_BORROW情况下进入循环, // 绝大多数情况p和mask的初始值应该都是非0值 while (cl->cmode == HTB_MAY_BORROW && p && mask) { // 备份掩码 m = mask; // 掩码清零 mask = 0; while (m) { // prio为m的第一个1值的位(取反后第一个0值的位) int prio = ffz(~m); // 去除该位 m &= ~(1 << prio); // 如果该类别prio对应的rb树是父节点中正在处理的 if (p->un.inner.ptr[prio] == cl->node + prio) { /* we are removing child which is pointed to from parent feed - forget the pointer but remember classid */ // 将cl的类别ID保存到last_ptr_id中prio对应位置 p->un.inner.last_ptr_id[prio] = cl->classid; // 清空父节点指向rb根指针 p->un.inner.ptr[prio] = NULL; } // 类别节点从与prio相应rb树中断开 htb_safe_rb_erase(cl->node + prio, p->un.inner.feed + prio); // 对已经空了的rb树保存其位置 if (!p->un.inner.feed[prio].rb_node) mask |= 1 << prio; } // 将已经空了的rb数掩码从父节点的活性值掩码中去掉 p->prio_activity &= ~mask; // 转到上一层处理 cl = p; p = cl->parent; } // 如果当前类别cl的模式是可以发送(无阻塞, 无借带宽), 将cl从ROW的相关树中断开 if (cl->cmode == HTB_CAN_SEND && mask) htb_remove_class_from_row(q, cl, mask); } /** * htb_remove_class_from_row - removes class from its row * * The class is removed from row at priorities marked in mask. * It does nothing if mask == 0. */ // mask为0时等价于一个空函数 static inline void htb_remove_class_from_row(struct htb_sched *q, struct htb_class *cl, int mask) { int m = 0; while (mask) { // prio为mask第一个1位的位置 int prio = ffz(~mask); // 去掉该位 mask &= ~(1 << prio); // 如果流控节点的该层该prio的rb树节点指向的是cl的prio的rb树节点, 更新到树的下一个rb节点 if (q->ptr[cl->level][prio] == cl->node + prio) htb_next_rb_node(q->ptr[cl->level] + prio); // 从ROW树中断开cl htb_safe_rb_erase(cl->node + prio, q->row[cl->level] + prio); // 如果该层该prio的rb树位空, 记录其位置 if (!q->row[cl->level][prio].rb_node) m |= 1 << prio; } // 在ROW掩码中将与rb树为空的那些prio位清空 q->row_mask[cl->level] &= ~m; } 5.11.4 初始化 static int htb_init(struct Qdisc *sch, struct rtattr *opt) { // HTB私有数据结构 struct htb_sched *q = qdisc_priv(sch); struct rtattr *tb[TCA_HTB_INIT]; struct tc_htb_glob *gopt; int i; // 检查用户空间传过来的初始化数据的合法性 if (!opt || rtattr_parse_nested(tb, TCA_HTB_INIT, opt) || tb[TCA_HTB_INIT - 1] == NULL || RTA_PAYLOAD(tb[TCA_HTB_INIT - 1]) < sizeof(*gopt)) { printk(KERN_ERR "HTB: hey probably you have bad tc tool ?\n"); return -EINVAL; } gopt = RTA_DATA(tb[TCA_HTB_INIT - 1]); // 检查版本信息是否匹配 if (gopt->version != HTB_VER >> 16) { printk(KERN_ERR "HTB: need tc/htb version %d (minor is %d), you have %d\n", HTB_VER >> 16, HTB_VER & 0xffff, gopt->version); return -EINVAL; } // 初始化各链表和哈希表结构 INIT_LIST_HEAD(&q->root); for (i = 0; i < HTB_HSIZE; i++) INIT_HLIST_HEAD(q->hash + i); for (i = 0; i < TC_HTB_NUMPRIO; i++) INIT_LIST_HEAD(q->drops + i); // 初始化定时器 init_timer(&q->timer); // 初始化HTB流控节点的直接发送的数据包队列 skb_queue_head_init(&q->direct_queue); // 直接发送队列长度初始化为网卡设备的发送队列长度, 至少为2 q->direct_qlen = sch->dev->tx_queue_len; if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */ q->direct_qlen = 2; // HTB定时函数 q->timer.function = htb_timer; q->timer.data = (unsigned long)sch; #ifdef HTB_RATECM // 使用HTB进行流控的情况 // 速率定时器初始化, 并开始定时 init_timer(&q->rttim); q->rttim.function = htb_rate_timer; q->rttim.data = (unsigned long)sch; q->rttim.expires = jiffies + HZ; add_timer(&q->rttim); #endif // 流量到定额转换参数, 是TC命令中的r2q参数 if ((q->rate2quantum = gopt->rate2quantum) < 1) q->rate2quantum = 1; // 缺省类别 q->defcls = gopt->defcls; return 0; } // HTB定时器函数 static void htb_timer(unsigned long arg) { struct Qdisc *sch = (struct Qdisc *)arg; // 去掉流控节点的阻塞标志 sch->flags &= ~TCQ_F_THROTTLED; wmb(); // 重新调度网卡 netif_schedule(sch->dev); } #ifdef HTB_RATECM // 递增试速率计算 #define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0 // HTB速率定时器函数 static void htb_rate_timer(unsigned long arg) { // HTB流控节点 struct Qdisc *sch = (struct Qdisc *)arg; // HTB私有数据结构 struct htb_sched *q = qdisc_priv(sch); struct hlist_node *p; struct htb_class *cl; /* lock queue so that we can muck with it */ spin_lock_bh(&sch->dev->queue_lock); // 定时一秒 q->rttim.expires = jiffies + HZ; // 再次添加定时器 add_timer(&q->rttim); /* scan and recompute one bucket at time */ // 每次更新计算一个哈希表的数据 if (++q->recmp_bucket >= HTB_HSIZE) q->recmp_bucket = 0; // 更新recmp_bucket所对应的哈希链表中每个类别节点的字节和数据包流量率 hlist_for_each_entry(cl,p, q->hash + q->recmp_bucket, hlist) { RT_GEN(cl->sum_bytes, cl->rate_bytes); RT_GEN(cl->sum_packets, cl->rate_packets); } spin_unlock_bh(&sch->dev->queue_lock); } #endif 5.11.5 丢包 /* try to drop from each class (by prio) until one succeed */ static unsigned int htb_drop(struct Qdisc *sch) { // HTB私有数据结构 struct htb_sched *q = qdisc_priv(sch); int prio; // 遍历各个级别的丢包链表, 最先操作的是7号链表, 最后操作的是0号链表 for (prio = TC_HTB_NUMPRIO - 1; prio >= 0; prio--) { struct list_head *p; // 遍历链表 list_for_each(p, q->drops + prio) { // 类别结构 struct htb_class *cl = list_entry(p, struct htb_class, un.leaf.drop_list); unsigned int len; // 如果该类别的叶子节点流控定义了丢包操作, 进行相应丢包操作 if (cl->un.leaf.q->ops->drop && (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) { // 丢包操作成功 sch->q.qlen--; // 子流控节点为空, 停止该类别 if (!cl->un.leaf.q->q.qlen) htb_deactivate(q, cl); return len; } } } return 0; } 5.11.6 复位 /* reset all classes */ /* always caled under BH & queue lock */ static void htb_reset(struct Qdisc *sch) { // HTB私有数据结构 struct htb_sched *q = qdisc_priv(sch); int i; // 遍历所有哈希表 for (i = 0; i < HTB_HSIZE; i++) { struct hlist_node *p; struct htb_class *cl; // 遍历链表中每个类别结构 hlist_for_each_entry(cl, p, q->hash + i, hlist) { if (cl->level) // 中间节点, 直接清零操作 memset(&cl->un.inner, 0, sizeof(cl->un.inner)); else { // 叶子节点, 复位内部流控结构 if (cl->un.leaf.q) qdisc_reset(cl->un.leaf.q); // 重新初始化丢弃链表 INIT_LIST_HEAD(&cl->un.leaf.drop_list); } cl->prio_activity = 0; cl->cmode = HTB_CAN_SEND; } } // 去掉阻塞标志 sch->flags &= ~TCQ_F_THROTTLED; // 删除定时器 del_timer(&q->timer); // 删除当前直接发送的数据包队列中的所有数据包 __skb_queue_purge(&q->direct_queue); // 参数清零 sch->q.qlen = 0; memset(q->row, 0, sizeof(q->row)); memset(q->row_mask, 0, sizeof(q->row_mask)); memset(q->wait_pq, 0, sizeof(q->wait_pq)); memset(q->ptr, 0, sizeof(q->ptr)); // 初始化丢弃队列 for (i = 0; i < TC_HTB_NUMPRIO; i++) INIT_LIST_HEAD(q->drops + i); } 5.11.7 释放 /* always caled under BH & queue lock */ static void htb_destroy(struct Qdisc *sch) { // HTB私有数据结构 struct htb_sched *q = qdisc_priv(sch); // 删除定时器 del_timer_sync(&q->timer); #ifdef HTB_RATECM del_timer_sync(&q->rttim); #endif /* This line used to be after htb_destroy_class call below and surprisingly it worked in 2.4. But it must precede it because filter need its target class alive to be able to call unbind_filter on it (without Oops). */ // 释放过滤器规则表 htb_destroy_filters(&q->filter_list); // 遍历当前的HTB类别树, 释放类别结构 while (!list_empty(&q->root)) htb_destroy_class(sch, list_entry(q->root.next, struct htb_class, sibling)); // 释放直接处理的数据队列 __skb_queue_purge(&q->direct_queue); } 5.11.8 输出HTB参数 static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) { // HTB私有数据结构 struct htb_sched *q = qdisc_priv(sch); unsigned char *b = skb->tail; struct rtattr *rta; struct tc_htb_glob gopt; spin_lock_bh(&sch->dev->queue_lock); // 直接发送的数据包数量 gopt.direct_pkts = q->direct_pkts; // HTB版本号 gopt.version = HTB_VER; // 类别转额度 gopt.rate2quantum = q->rate2quantum; // 缺省类别 gopt.defcls = q->defcls; gopt.debug = 0; // 返回数据在数据包中的具体位置 rta = (struct rtattr *)b; RTA_PUT(skb, TCA_OPTIONS, 0, NULL); // 填入选项参数 RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt); rta->rta_len = skb->tail - b; spin_unlock_bh(&sch->dev->queue_lock); return skb->len; rtattr_failure: spin_unlock_bh(&sch->dev->queue_lock); skb_trim(skb, skb->tail - skb->data); return -1; } ...... 待续 ......
发表评论
-
Linux内核中流量控制(24)
2011-01-10 16:33 2244本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(23)
2011-01-10 16:30 1530本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(22)
2011-01-10 16:29 1978本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(21)
2011-01-10 16:28 1399本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(20)
2011-01-10 16:27 1566本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(19)
2011-01-10 16:27 2020本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(18)
2011-01-10 16:26 1614Linux内核中流量控制(18) ... -
Linux内核中流量控制(17)
2011-01-10 16:25 1989本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(16)
2011-01-10 16:25 1847本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(15)
2011-01-10 16:24 1978本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(14)
2011-01-10 16:23 2000本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(13)
2011-01-10 16:22 2685本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(11)
2011-01-10 16:21 3287本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(10)
2011-01-10 16:20 2040本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(9)
2011-01-10 16:19 1874本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(8)
2011-01-10 16:18 1542本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(7)
2011-01-10 16:18 2971本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(6)
2011-01-10 16:17 1537本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(5)
2011-01-10 16:16 1766本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(4)
2011-01-10 16:15 1687本文档的Copyleft归yfydz所有,使用GPL发布,可以 ...
相关推荐
在Linux内核中,TCP和UDP模块处理连接建立、数据传输、流量控制和拥塞控制等问题。 5. **应用层**:这一层包含各种应用协议,如HTTP、FTP、SMTP等,它们直接与用户交互。Linux内核通过socket API为上层应用提供了与...
【基于Linux内核的BT流量控制的原理与实现】 Linux操作系统以其开源、可定制的特点,在系统开发领域广泛应用,尤其在网络流量控制方面具有显著优势。针对BitTorrent(BT)这种大量占用带宽的P2P协议,Linux内核提供...
4. **网络堆栈**:从硬件接口到应用层协议的整个网络传输流程,如TCP/IP协议族、套接字API、网络设备驱动程序以及流量控制策略。 5. **设备驱动**:内核如何与硬件交互,驱动程序的工作原理,包括字符设备、块设备...
通过分析源码,我们可以了解到数据包的接收与发送过程,理解TCP连接的建立与断开、拥塞控制、流量控制等机制,这对于网络编程和网络故障排查非常有帮助。 此外,Linux内核还涉及中断处理、设备驱动、I/O管理等多个...
【基于Linux内核扩展模块的P2P流量控制】这篇文献主要探讨了如何在Linux操作系统中,通过内核扩展模块来实现对P2P流量的有效控制。P2P(Peer-to-Peer)技术的兴起改变了互联网的中心化结构,使得资源分享更为便捷,...
基于Linux内核扩展模块的P2P流量控制
基于LQL库的流量控制方法可以直接在Linux内核的框架下实现,而不需要使用传统方法中的TC命令解析、netlink传输和内核空间执行的三层结构。这可以提高流量控制的效率和可靠性,同时也可以减少流量控制的延迟和资源...
书中的内容涵盖了从内核基础到高级技术的方方面面,为那些希望提升Linux内核理解和开发能力的读者提供了宝贵的资源。在本文中,我们将探讨几个关键的知识点,包括Linux内核的基本结构、进程管理、内存管理和设备驱动...
2.6.24版本在网络方面加强了IPv6的支持,并改进了网络流量控制算法。 6. **安全与权限管理**:Linux内核采用了用户和组的概念,通过权限系统(如chmod、chown等)来控制文件访问。此外,还有SELinux(Security-...
接着,作者深入剖析了网络设备数据结构net_device,它包含了设备的配置信息、统计信息、状态标志以及各种管理列表和流量控制字段,这些细节揭示了网络设备如何在内核中被抽象和管理。 通过以上内容,我们可以看到,...
它处理网络数据的接收和发送,进行网络层的路由选择,以及传输层的拥塞控制和流量控制。 5. **设备驱动**:设备驱动程序是内核与硬件之间的桥梁,使得内核能够控制硬件设备。Linux内核支持大量设备驱动,包括块设备...
在Linux操作系统中,高级路由和流量控制是网络管理员和系统管理员必须掌握的关键技能。这篇文档“Linux高级路由和流量控制HOWTO中文版”由牛老师翻译,为读者提供了深入理解这些概念的宝贵资源。以下是对其中核心...
该模型内置于Linux内核中,并利用队列算法对不同服务质量(Quality of Service, QoS)需求的数据流进行分类,以提供灵活且差异化的服务。实验结果表明,采用该流量控制模型后,网络性能显著提高,并能很好地适应未来...
同时,还会讨论TCP的流量控制和拥塞控制机制,如滑动窗口、慢启动、快速重传和快速恢复算法等,这些都是保证网络通信质量和效率的关键。 其次,关于IP协议,书里会涉及IP地址、子网掩码、路由选择等概念,以及IP分...
TC 工具基于 Linux 内核的网络设备驱动程序,通过对网络设备的控制,来实现流量控制。TC 的工作原理可以分为以下三个阶段: 1. 流量控制方式:TC 提供了多种流量控制方式,包括 Token Bucket Filter(TBF)、...
TC(Linux 下流量控制工具)详细说明及应用实例 TC 是 Linux 下的一种流量控制工具,用于控制和管理网络流量。它提供了一个灵活的方式来管理网络带宽、延迟和丢包率等网络性能参数,以满足不同应用场景的需求。 TC...
2. **TCP/IP协议**:在传输层,TCP(传输控制协议)提供可靠的数据传输服务,通过确认、重传和流量控制确保数据的完整性和顺序。IP(互联网协议)在网络层负责数据包的路由和分片,是互联网的基础协议。 3. **套接...
Linux内核中的sock和socket数据结构是网络编程的核心组成部分,它们是实现网络通信的基础构件。在Linux操作系统中,网络通信的实现依赖于BSD套接字接口,而这一接口在内核中是通过sock和socket数据结构来实现的。 ...